wasapi: Support multiple devices in the device list on Windows UWP/WinRT platform. All UWP/WinRT functions are now prefixed as PaWasapiWinrt_ to be clearly visible, therefore PaWasapi_SetDefaultInterfaceId() was renamed to PaWasapiWinrt_SetDefaultDeviceId(). Expanded Important notes regarding UWP/WinRT platform and how to make the fully-functional device list with the corresponding pseudo-code example for easier understanding of the functionality.
This commit is contained in:
parent
522f982158
commit
a5fb8d94aa
2 changed files with 360 additions and 135 deletions
|
|
@ -516,28 +516,6 @@ PaError PaWasapi_GetJackCount( PaDeviceIndex device, int *pJackCount );
|
||||||
PaError PaWasapi_GetJackDescription( PaDeviceIndex device, int jackIndex, PaWasapiJackDescription *pJackDescription );
|
PaError PaWasapi_GetJackDescription( PaDeviceIndex device, int jackIndex, PaWasapiJackDescription *pJackDescription );
|
||||||
|
|
||||||
|
|
||||||
/** Set default interface Id.
|
|
||||||
|
|
||||||
By default PA implementation will use DEVINTERFACE_AUDIO_RENDER and
|
|
||||||
DEVINTERFACE_AUDIO_CAPTURE if device Id is not provided explicitly. These default Ids
|
|
||||||
will not allow to use Exclusive mode on UWP platform and thus you must provide
|
|
||||||
device Id explicitly via this API before calling Pa_OpenStream().
|
|
||||||
Device Ids on UWP platform are obtainable via
|
|
||||||
Windows::Media::Devices::MediaDevice::GetDefaultAudioRenderId() or
|
|
||||||
Windows::Media::Devices::MediaDevice::GetDefaultAudioCaptureId() API.
|
|
||||||
|
|
||||||
@note UWP platform only.
|
|
||||||
|
|
||||||
@param pId Interface Id, pointer to the 16-bit Unicode string (WCHAR). If NULL then device Id
|
|
||||||
will be reset to the default, e.g. DEVINTERFACE_AUDIO_RENDER or DEVINTERFACE_AUDIO_CAPTURE.
|
|
||||||
@param bOutput TRUE (1) for output (render), FALSE (0) for input (capture).
|
|
||||||
|
|
||||||
@return Error code indicating success or failure. Will return paIncompatibleStreamHostApi if PA is not compiled
|
|
||||||
for UWP platform. If Id is longer than 4096 characters paBufferTooBig will be returned.
|
|
||||||
*/
|
|
||||||
PaError PaWasapi_SetDefaultInterfaceId( unsigned short *pId, int bOutput );
|
|
||||||
|
|
||||||
|
|
||||||
/** Set stream state handler.
|
/** Set stream state handler.
|
||||||
|
|
||||||
@param pStream Pointer to PaStream object.
|
@param pStream Pointer to PaStream object.
|
||||||
|
|
@ -549,6 +527,74 @@ PaError PaWasapi_SetDefaultInterfaceId( unsigned short *pId, int bOutput );
|
||||||
PaError PaWasapi_SetStreamStateHandler( PaStream *pStream, PaWasapiStreamStateCallback fnStateHandler, void *pUserData );
|
PaError PaWasapi_SetStreamStateHandler( PaStream *pStream, PaWasapiStreamStateCallback fnStateHandler, void *pUserData );
|
||||||
|
|
||||||
|
|
||||||
|
/** Set default device Id.
|
||||||
|
|
||||||
|
By default implementation will use the DEVINTERFACE_AUDIO_RENDER and
|
||||||
|
DEVINTERFACE_AUDIO_CAPTURE Ids if device Id is not provided explicitly. These default Ids
|
||||||
|
will not allow to use Exclusive mode on UWP/WinRT platform and thus you must provide
|
||||||
|
device Id explicitly via this API before calling the Pa_OpenStream().
|
||||||
|
|
||||||
|
Device Ids on UWP platform are obtainable via:
|
||||||
|
Windows::Media::Devices::MediaDevice::GetDefaultAudioRenderId() or
|
||||||
|
Windows::Media::Devices::MediaDevice::GetDefaultAudioCaptureId() API.
|
||||||
|
|
||||||
|
After the call completes, memory referenced by pointers can be freed, as implementation keeps its own copy.
|
||||||
|
|
||||||
|
Call this function before calling Pa_IsFormatSupported() when Exclusive mode is requested.
|
||||||
|
|
||||||
|
See an example in the IMPORTANT notes.
|
||||||
|
|
||||||
|
@note UWP/WinRT platform only.
|
||||||
|
|
||||||
|
@param pId Device Id, pointer to the 16-bit Unicode string (WCHAR). If NULL then device Id
|
||||||
|
will be reset to the default, e.g. DEVINTERFACE_AUDIO_RENDER or DEVINTERFACE_AUDIO_CAPTURE.
|
||||||
|
@param bOutput TRUE (1) for output (render), FALSE (0) for input (capture).
|
||||||
|
|
||||||
|
@return Error code indicating success or failure. Will return paIncompatibleStreamHostApi if library is not compiled
|
||||||
|
for UWP/WinRT platform. If Id is longer than PA_WASAPI_DEVICE_ID_LEN characters paBufferTooBig will
|
||||||
|
be returned.
|
||||||
|
*/
|
||||||
|
PaError PaWasapiWinrt_SetDefaultDeviceId( const unsigned short *pId, int bOutput );
|
||||||
|
|
||||||
|
|
||||||
|
/** Populate the device list.
|
||||||
|
|
||||||
|
By default the implementation will rely on DEVINTERFACE_AUDIO_RENDER and DEVINTERFACE_AUDIO_CAPTURE as
|
||||||
|
default devices. If device Id is provided by PaWasapiWinrt_SetDefaultDeviceId() then those
|
||||||
|
device Ids will be used as default and only devices for the device list.
|
||||||
|
|
||||||
|
By populating the device list you can provide an additional available audio devices of the system to PA
|
||||||
|
which are obtainable by:
|
||||||
|
Windows::Devices::Enumeration::DeviceInformation::FindAllAsync(selector) where selector is obtainable by
|
||||||
|
Windows::Media::Devices::MediaDevice::GetAudioRenderSelector() or
|
||||||
|
Windows::Media::Devices::MediaDevice::GetAudioCaptureSelector() API.
|
||||||
|
|
||||||
|
After the call completes, memory referenced by pointers can be freed, as implementation keeps its own copy.
|
||||||
|
|
||||||
|
You must call PaWasapi_UpdateDeviceList() to update the internal device list of the implementation after
|
||||||
|
calling this function.
|
||||||
|
|
||||||
|
See an example in the IMPORTANT notes.
|
||||||
|
|
||||||
|
@note UWP/WinRT platform only.
|
||||||
|
|
||||||
|
@param pId Array of device Ids, pointer to the array of pointers of 16-bit Unicode string (WCHAR). If NULL
|
||||||
|
and count is also 0 then device Ids will be reset to the default. Required.
|
||||||
|
@param pName Array of device Names, pointer to the array of pointers of 16-bit Unicode string (WCHAR). Optional.
|
||||||
|
@param pRole Array of device Roles, see PaWasapiDeviceRole and PaWasapi_GetDeviceRole() for more details. Optional.
|
||||||
|
@param count Number of devices, the number of array elements (pId, pName, pRole). Maximum count of devices
|
||||||
|
is limited by PA_WASAPI_DEVICE_MAX_COUNT.
|
||||||
|
@param bOutput TRUE (1) for output (render), FALSE (0) for input (capture).
|
||||||
|
|
||||||
|
@return Error code indicating success or failure. Will return paIncompatibleStreamHostApi if library is not compiled
|
||||||
|
for UWP/WinRT platform. If Id is longer than PA_WASAPI_DEVICE_ID_LEN characters paBufferTooBig will
|
||||||
|
be returned. If Name is longer than PA_WASAPI_DEVICE_NAME_LEN characters paBufferTooBig will
|
||||||
|
be returned.
|
||||||
|
*/
|
||||||
|
PaError PaWasapiWinrt_PopulateDeviceList( const unsigned short **pId, const unsigned short **pName,
|
||||||
|
const PaWasapiDeviceRole *pRole, unsigned int count, int bOutput );
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
IMPORTANT:
|
IMPORTANT:
|
||||||
|
|
||||||
|
|
@ -626,6 +672,44 @@ PaError PaWasapi_SetStreamStateHandler( PaStream *pStream, PaWasapiStreamStateCa
|
||||||
2) pXXX - pointer
|
2) pXXX - pointer
|
||||||
3) fnXXX - pointer to function
|
3) fnXXX - pointer to function
|
||||||
4) structure members are never prefixed with a type distinguisher
|
4) structure members are never prefixed with a type distinguisher
|
||||||
|
|
||||||
|
|
||||||
|
UWP/WinRT:
|
||||||
|
|
||||||
|
This platform has number of limitations which do not allow to enumerate audio devices without
|
||||||
|
an additional external help. Enumeration is possible though from C++/CX, check the related API
|
||||||
|
Windows::Devices::Enumeration::DeviceInformation::FindAllAsync().
|
||||||
|
|
||||||
|
The main limitation is an absence of the device enumeration from inside the PA's implementation.
|
||||||
|
This problem can be solved by using the following functions:
|
||||||
|
|
||||||
|
PaWasapiWinrt_SetDefaultDeviceId() - to set default input/output device,
|
||||||
|
PaWasapiWinrt_PopulateDeviceList() - to populate device list with devices.
|
||||||
|
|
||||||
|
Here is an example of populating the device list which can also be updated dynamically depending on
|
||||||
|
whether device was removed from or added to the system:
|
||||||
|
|
||||||
|
----------------
|
||||||
|
|
||||||
|
std::vector<const UINT16 *> ids, names;
|
||||||
|
std::vector<PaWasapiDeviceRole> role;
|
||||||
|
|
||||||
|
ids.resize(count);
|
||||||
|
names.resize(count);
|
||||||
|
role.resize(count);
|
||||||
|
|
||||||
|
for (UINT32 i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
ids[i] = (const UINT16 *)device_ids[i].c_str();
|
||||||
|
names[i] = (const UINT16 *)device_names[i].c_str();
|
||||||
|
role[i] = eRoleUnknownFormFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
PaWasapiWinrt_SetDefaultDeviceId((const UINT16 *)default_device_id.c_str(), !capture);
|
||||||
|
PaWasapiWinrt_PopulateDeviceList(ids.data(), names.data(), role.data(), count, !capture);
|
||||||
|
PaWasapi_UpdateDeviceList();
|
||||||
|
|
||||||
|
----------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
|
|
@ -309,10 +309,10 @@ PA_THREAD_FUNC ProcThreadPoll(void *param);
|
||||||
#define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000
|
#define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_STR_LEN 512
|
#define PA_WASAPI_DEVICE_ID_LEN 256
|
||||||
|
#define PA_WASAPI_DEVICE_NAME_LEN 128
|
||||||
#ifdef PA_WINRT
|
#ifdef PA_WINRT
|
||||||
#define PA_WASAPI_DEVICE_ID_LEN 4096
|
#define PA_WASAPI_DEVICE_MAX_COUNT 16
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum { S_INPUT = 0, S_OUTPUT = 1, S_COUNT = 2, S_FULLDUPLEX = 0 };
|
enum { S_INPUT = 0, S_OUTPUT = 1, S_COUNT = 2, S_FULLDUPLEX = 0 };
|
||||||
|
|
@ -430,8 +430,8 @@ typedef struct PaWasapiDeviceInfo
|
||||||
IMMDevice *device;
|
IMMDevice *device;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// from GetId
|
// device Id
|
||||||
WCHAR szDeviceID[MAX_STR_LEN];
|
WCHAR deviceId[PA_WASAPI_DEVICE_ID_LEN];
|
||||||
|
|
||||||
// from GetState
|
// from GetState
|
||||||
DWORD state;
|
DWORD state;
|
||||||
|
|
@ -450,7 +450,7 @@ typedef struct PaWasapiDeviceInfo
|
||||||
// Fields filled from IMMEndpoint'sGetDataFlow
|
// Fields filled from IMMEndpoint'sGetDataFlow
|
||||||
EDataFlow flow;
|
EDataFlow flow;
|
||||||
|
|
||||||
// Formfactor
|
// Form-factor
|
||||||
EndpointFormFactor formFactor;
|
EndpointFormFactor formFactor;
|
||||||
}
|
}
|
||||||
PaWasapiDeviceInfo;
|
PaWasapiDeviceInfo;
|
||||||
|
|
@ -623,10 +623,44 @@ static void *PaWasapi_ReallocateMemory(void *prev, size_t size);
|
||||||
static void PaWasapi_FreeMemory(void *ptr);
|
static void PaWasapi_FreeMemory(void *ptr);
|
||||||
static PaSampleFormat WaveToPaFormat(const WAVEFORMATEXTENSIBLE *fmtext);
|
static PaSampleFormat WaveToPaFormat(const WAVEFORMATEXTENSIBLE *fmtext);
|
||||||
|
|
||||||
// Local statics
|
// WinRT (UWP) device list
|
||||||
#ifdef PA_WINRT
|
#ifdef PA_WINRT
|
||||||
static OLECHAR g_DefaultRenderId[PA_WASAPI_DEVICE_ID_LEN] = { 0 };
|
typedef struct PaWasapiWinrtDeviceInfo
|
||||||
static OLECHAR g_DefaultCaptureId[PA_WASAPI_DEVICE_ID_LEN] = { 0 };
|
{
|
||||||
|
WCHAR id[PA_WASAPI_DEVICE_ID_LEN];
|
||||||
|
WCHAR name[PA_WASAPI_DEVICE_NAME_LEN];
|
||||||
|
EndpointFormFactor formFactor;
|
||||||
|
}
|
||||||
|
PaWasapiWinrtDeviceInfo;
|
||||||
|
typedef struct PaWasapiWinrtDeviceListRole
|
||||||
|
{
|
||||||
|
WCHAR defaultId[PA_WASAPI_DEVICE_ID_LEN];
|
||||||
|
PaWasapiWinrtDeviceInfo devices[PA_WASAPI_DEVICE_MAX_COUNT];
|
||||||
|
UINT32 deviceCount;
|
||||||
|
}
|
||||||
|
PaWasapiWinrtDeviceListRole;
|
||||||
|
typedef struct PaWasapiWinrtDeviceList
|
||||||
|
{
|
||||||
|
PaWasapiWinrtDeviceListRole render;
|
||||||
|
PaWasapiWinrtDeviceListRole capture;
|
||||||
|
}
|
||||||
|
PaWasapiWinrtDeviceList;
|
||||||
|
static PaWasapiWinrtDeviceList g_DeviceListInfo = { 0 };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// WinRT (UWP) device list context
|
||||||
|
#ifdef PA_WINRT
|
||||||
|
typedef struct PaWasapiWinrtDeviceListContextEntry
|
||||||
|
{
|
||||||
|
PaWasapiWinrtDeviceInfo *info;
|
||||||
|
EDataFlow flow;
|
||||||
|
}
|
||||||
|
PaWasapiWinrtDeviceListContextEntry;
|
||||||
|
typedef struct PaWasapiWinrtDeviceListContext
|
||||||
|
{
|
||||||
|
PaWasapiWinrtDeviceListContextEntry devices[PA_WASAPI_DEVICE_MAX_COUNT * 2];
|
||||||
|
}
|
||||||
|
PaWasapiWinrtDeviceListContext;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
|
|
@ -1593,65 +1627,72 @@ static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Acti
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCompletionHandler(const IID *iid, void **obj)
|
static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCompletionHandler(const IID *iid, void **client)
|
||||||
{
|
{
|
||||||
PaActivateAudioInterfaceCompletionHandler *handler = PaUtil_AllocateMemory(sizeof(PaActivateAudioInterfaceCompletionHandler));
|
PaActivateAudioInterfaceCompletionHandler *handler = PaUtil_AllocateMemory(sizeof(PaActivateAudioInterfaceCompletionHandler));
|
||||||
ZeroMemory(handler, sizeof(*handler));
|
|
||||||
|
memset(handler, 0, sizeof(*handler));
|
||||||
|
|
||||||
handler->parent.lpVtbl = PaUtil_AllocateMemory(sizeof(*handler->parent.lpVtbl));
|
handler->parent.lpVtbl = PaUtil_AllocateMemory(sizeof(*handler->parent.lpVtbl));
|
||||||
handler->parent.lpVtbl->QueryInterface = &PaActivateAudioInterfaceCompletionHandler_QueryInterface;
|
handler->parent.lpVtbl->QueryInterface = &PaActivateAudioInterfaceCompletionHandler_QueryInterface;
|
||||||
handler->parent.lpVtbl->AddRef = &PaActivateAudioInterfaceCompletionHandler_AddRef;
|
handler->parent.lpVtbl->AddRef = &PaActivateAudioInterfaceCompletionHandler_AddRef;
|
||||||
handler->parent.lpVtbl->Release = &PaActivateAudioInterfaceCompletionHandler_Release;
|
handler->parent.lpVtbl->Release = &PaActivateAudioInterfaceCompletionHandler_Release;
|
||||||
handler->parent.lpVtbl->ActivateCompleted = &PaActivateAudioInterfaceCompletionHandler_ActivateCompleted;
|
handler->parent.lpVtbl->ActivateCompleted = &PaActivateAudioInterfaceCompletionHandler_ActivateCompleted;
|
||||||
handler->refs = 1;
|
handler->refs = 1;
|
||||||
handler->in.iid = iid;
|
handler->in.iid = iid;
|
||||||
handler->in.obj = obj;
|
handler->in.obj = client;
|
||||||
|
|
||||||
return (IActivateAudioInterfaceCompletionHandler *)handler;
|
return (IActivateAudioInterfaceCompletionHandler *)handler;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
#ifdef PA_WINRT
|
#ifdef PA_WINRT
|
||||||
static HRESULT ActivateAudioInterface_WINRT(EDataFlow flow, const IID *iid, void **obj)
|
static HRESULT WinRT_GetDefaultDeviceId(WCHAR *deviceId, UINT32 deviceIdMax, EDataFlow flow)
|
||||||
{
|
{
|
||||||
#define PA_WASAPI_DEVICE_PATH_LEN 64
|
|
||||||
|
|
||||||
PaError result = paNoError;
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
IActivateAudioInterfaceAsyncOperation *asyncOp = NULL;
|
|
||||||
IActivateAudioInterfaceCompletionHandler *handler = CreateActivateAudioInterfaceCompletionHandler(iid, obj);
|
|
||||||
PaActivateAudioInterfaceCompletionHandler *handlerImpl = (PaActivateAudioInterfaceCompletionHandler *)handler;
|
|
||||||
OLECHAR tmp[PA_WASAPI_DEVICE_PATH_LEN] = { 0 };
|
|
||||||
OLECHAR *devicePath = tmp;
|
|
||||||
|
|
||||||
// Get device path in form L"{DEVICE_GUID}"
|
|
||||||
switch (flow)
|
switch (flow)
|
||||||
{
|
{
|
||||||
case eRender:
|
case eRender:
|
||||||
if (g_DefaultRenderId[0] != 0)
|
if (g_DeviceListInfo.render.defaultId[0] != 0)
|
||||||
devicePath = g_DefaultRenderId;
|
wcsncpy_s(deviceId, deviceIdMax, g_DeviceListInfo.render.defaultId, wcslen(g_DeviceListInfo.render.defaultId));
|
||||||
else
|
else
|
||||||
StringFromGUID2(&DEVINTERFACE_AUDIO_RENDER, devicePath, PA_WASAPI_DEVICE_PATH_LEN - 1);
|
StringFromGUID2(&DEVINTERFACE_AUDIO_RENDER, deviceId, deviceIdMax);
|
||||||
break;
|
break;
|
||||||
case eCapture:
|
case eCapture:
|
||||||
if (g_DefaultCaptureId[0] != 0)
|
if (g_DeviceListInfo.capture.defaultId[0] != 0)
|
||||||
devicePath = g_DefaultCaptureId;
|
wcsncpy_s(deviceId, deviceIdMax, g_DeviceListInfo.capture.defaultId, wcslen(g_DeviceListInfo.capture.defaultId));
|
||||||
else
|
else
|
||||||
StringFromGUID2(&DEVINTERFACE_AUDIO_CAPTURE, devicePath, PA_WASAPI_DEVICE_PATH_LEN - 1);
|
StringFromGUID2(&DEVINTERFACE_AUDIO_CAPTURE, deviceId, deviceIdMax);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------
|
||||||
|
#ifdef PA_WINRT
|
||||||
|
static HRESULT WinRT_ActivateAudioInterface(const WCHAR *deviceId, const IID *iid, void **client)
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
IActivateAudioInterfaceAsyncOperation *asyncOp = NULL;
|
||||||
|
IActivateAudioInterfaceCompletionHandler *handler = CreateActivateAudioInterfaceCompletionHandler(iid, client);
|
||||||
|
PaActivateAudioInterfaceCompletionHandler *handlerImpl = (PaActivateAudioInterfaceCompletionHandler *)handler;
|
||||||
|
UINT32 sleepToggle = 0;
|
||||||
|
|
||||||
// Async operation will call back to IActivateAudioInterfaceCompletionHandler::ActivateCompleted
|
// Async operation will call back to IActivateAudioInterfaceCompletionHandler::ActivateCompleted
|
||||||
// which must be an agile interface implementation
|
// which must be an agile interface implementation
|
||||||
hr = ActivateAudioInterfaceAsync(devicePath, iid, NULL, handler, &asyncOp);
|
hr = ActivateAudioInterfaceAsync(deviceId, iid, NULL, handler, &asyncOp);
|
||||||
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
||||||
|
|
||||||
// Wait in busy loop for async operation to complete
|
// 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
|
// Use Interlocked API here to ensure that ->done variable is read every time through the loop
|
||||||
while (SUCCEEDED(hr) && !InterlockedOr(&handlerImpl->done, 0))
|
while (SUCCEEDED(hr) && !InterlockedOr(&handlerImpl->done, 0))
|
||||||
{
|
{
|
||||||
Sleep(1);
|
Sleep(sleepToggle ^= 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = handlerImpl->out.hr;
|
hr = handlerImpl->out.hr;
|
||||||
|
|
@ -1662,8 +1703,6 @@ error:
|
||||||
SAFE_RELEASE(handler);
|
SAFE_RELEASE(handler);
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
#undef PA_WASAPI_DEVICE_PATH_LEN
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -1677,7 +1716,7 @@ static HRESULT ActivateAudioInterface(const PaWasapiDeviceInfo *deviceInfo, cons
|
||||||
if (FAILED(hr = IMMDevice_Activate(deviceInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)client)))
|
if (FAILED(hr = IMMDevice_Activate(deviceInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)client)))
|
||||||
return hr;
|
return hr;
|
||||||
#else
|
#else
|
||||||
if (FAILED(hr = ActivateAudioInterface_WINRT(deviceInfo->flow, GetAudioClientIID(), (void **)client)))
|
if (FAILED(hr = WinRT_ActivateAudioInterface(deviceInfo->deviceId, GetAudioClientIID(), (void **)client)))
|
||||||
return hr;
|
return hr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -1766,37 +1805,41 @@ static PaError FillInactiveDeviceInfo(PaWasapiHostApiRepresentation *paWasapi, P
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
static PaError FillDeviceInfo(PaWasapiHostApiRepresentation *paWasapi, void *pEndPoints, INT32 index, const WCHAR *defaultRenderer,
|
static PaError FillDeviceInfo(PaWasapiHostApiRepresentation *paWasapi, void *pEndPoints, INT32 index, const WCHAR *defaultRenderId,
|
||||||
const WCHAR *defaultCapturer, PaDeviceInfo *deviceInfo, PaWasapiDeviceInfo *wasapiDeviceInfo)
|
const WCHAR *defaultCaptureId, PaDeviceInfo *deviceInfo, PaWasapiDeviceInfo *wasapiDeviceInfo
|
||||||
|
#ifdef PA_WINRT
|
||||||
|
, PaWasapiWinrtDeviceListContext *deviceListContext
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
PaError result;
|
PaError result;
|
||||||
PaUtilHostApiRepresentation *hostApi = (PaUtilHostApiRepresentation *)paWasapi;
|
PaUtilHostApiRepresentation *hostApi = (PaUtilHostApiRepresentation *)paWasapi;
|
||||||
|
#ifdef PA_WINRT
|
||||||
|
PaWasapiWinrtDeviceListContextEntry *listEntry = &deviceListContext->devices[index];
|
||||||
|
(void)pEndPoints;
|
||||||
|
(void)defaultRenderId;
|
||||||
|
(void)defaultCaptureId;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef PA_WINRT
|
#ifndef PA_WINRT
|
||||||
hr = IMMDeviceCollection_Item((IMMDeviceCollection *)pEndPoints, index, &wasapiDeviceInfo->device);
|
hr = IMMDeviceCollection_Item((IMMDeviceCollection *)pEndPoints, index, &wasapiDeviceInfo->device);
|
||||||
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
||||||
|
|
||||||
// getting ID
|
// Get device Id
|
||||||
{
|
{
|
||||||
WCHAR *pszDeviceId;
|
WCHAR *deviceId;
|
||||||
|
|
||||||
hr = IMMDevice_GetId(wasapiDeviceInfo->device, &pszDeviceId);
|
hr = IMMDevice_GetId(wasapiDeviceInfo->device, &deviceId);
|
||||||
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
||||||
|
|
||||||
wcsncpy(wasapiDeviceInfo->szDeviceID, pszDeviceId, MAX_STR_LEN - 1);
|
wcsncpy(wasapiDeviceInfo->deviceId, deviceId, PA_WASAPI_DEVICE_ID_LEN - 1);
|
||||||
CoTaskMemFree(pszDeviceId);
|
CoTaskMemFree(deviceId);
|
||||||
|
|
||||||
if ((defaultCapturer != NULL) && (lstrcmpW(wasapiDeviceInfo->szDeviceID, defaultCapturer) == 0))
|
|
||||||
hostApi->info.defaultInputDevice = hostApi->info.deviceCount;
|
|
||||||
|
|
||||||
if ((defaultRenderer != NULL) && (lstrcmpW(wasapiDeviceInfo->szDeviceID, defaultRenderer) == 0))
|
|
||||||
hostApi->info.defaultOutputDevice = hostApi->info.deviceCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get state of the device
|
||||||
hr = IMMDevice_GetState(wasapiDeviceInfo->device, &wasapiDeviceInfo->state);
|
hr = IMMDevice_GetState(wasapiDeviceInfo->device, &wasapiDeviceInfo->state);
|
||||||
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
||||||
|
|
||||||
if (wasapiDeviceInfo->state != DEVICE_STATE_ACTIVE)
|
if (wasapiDeviceInfo->state != DEVICE_STATE_ACTIVE)
|
||||||
{
|
{
|
||||||
PRINT(("WASAPI device: %d is not currently available (state:%d)\n", index, wasapiDeviceInfo->state));
|
PRINT(("WASAPI device: %d is not currently available (state:%d)\n", index, wasapiDeviceInfo->state));
|
||||||
|
|
@ -1818,16 +1861,16 @@ static PaError FillDeviceInfo(PaWasapiHostApiRepresentation *paWasapi, void *pEn
|
||||||
hr = IPropertyStore_GetValue(pProperty, &PKEY_Device_FriendlyName, &value);
|
hr = IPropertyStore_GetValue(pProperty, &PKEY_Device_FriendlyName, &value);
|
||||||
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
||||||
|
|
||||||
if ((deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1)) == NULL)
|
if ((deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, PA_WASAPI_DEVICE_NAME_LEN)) == NULL)
|
||||||
{
|
{
|
||||||
result = paInsufficientMemory;
|
result = paInsufficientMemory;
|
||||||
PropVariantClear(&value);
|
PropVariantClear(&value);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (value.pwszVal)
|
if (value.pwszVal)
|
||||||
WideCharToMultiByte(CP_UTF8, 0, value.pwszVal, (int)wcslen(value.pwszVal), (char *)deviceInfo->name, MAX_STR_LEN - 1, 0, 0);
|
WideCharToMultiByte(CP_UTF8, 0, value.pwszVal, (INT32)wcslen(value.pwszVal), (char *)deviceInfo->name, PA_WASAPI_DEVICE_NAME_LEN - 1, 0, 0);
|
||||||
else
|
else
|
||||||
_snprintf((char *)deviceInfo->name, MAX_STR_LEN - 1, "baddev%d", index);
|
_snprintf((char *)deviceInfo->name, PA_WASAPI_DEVICE_NAME_LEN - 1, "baddev%d", index);
|
||||||
|
|
||||||
PropVariantClear(&value);
|
PropVariantClear(&value);
|
||||||
|
|
||||||
|
|
@ -1879,24 +1922,39 @@ static PaError FillDeviceInfo(PaWasapiHostApiRepresentation *paWasapi, void *pEn
|
||||||
SAFE_RELEASE(pProperty);
|
SAFE_RELEASE(pProperty);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(void)pEndPoints;
|
// Set device Id
|
||||||
(void)defaultRenderer;
|
wcsncpy(wasapiDeviceInfo->deviceId, listEntry->info->id, PA_WASAPI_DEVICE_ID_LEN - 1);
|
||||||
(void)defaultCapturer;
|
|
||||||
|
// Set device name
|
||||||
|
if ((deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, PA_WASAPI_DEVICE_NAME_LEN)) == NULL)
|
||||||
|
{
|
||||||
|
result = paInsufficientMemory;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
((char *)deviceInfo->name)[0] = 0;
|
||||||
|
if (listEntry->info->name[0] != 0)
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, listEntry->info->name, (INT32)wcslen(listEntry->info->name), (char *)deviceInfo->name, PA_WASAPI_DEVICE_NAME_LEN - 1, 0, 0);
|
||||||
|
if (deviceInfo->name[0] == 0) // fallback if WideCharToMultiByte is failed, or listEntry is nameless
|
||||||
|
_snprintf((char *)deviceInfo->name, PA_WASAPI_DEVICE_NAME_LEN - 1, "WASAPI_%s:%d", (listEntry->flow == eRender ? "Output" : "Input"), index);
|
||||||
|
|
||||||
|
// Form-factor
|
||||||
|
wasapiDeviceInfo->formFactor = listEntry->info->formFactor;
|
||||||
|
|
||||||
|
// Set data flow
|
||||||
|
wasapiDeviceInfo->flow = listEntry->flow;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Getting a temporary IAudioClient for more fields
|
// Set default Output/Input devices
|
||||||
// we make sure NOT to call Initialize yet!
|
if ((defaultRenderId != NULL) && (wcsncmp(wasapiDeviceInfo->deviceId, defaultRenderId, PA_WASAPI_DEVICE_NAME_LEN - 1) == 0))
|
||||||
|
hostApi->info.defaultOutputDevice = hostApi->info.deviceCount;
|
||||||
|
if ((defaultCaptureId != NULL) && (wcsncmp(wasapiDeviceInfo->deviceId, defaultCaptureId, PA_WASAPI_DEVICE_NAME_LEN - 1) == 0))
|
||||||
|
hostApi->info.defaultInputDevice = hostApi->info.deviceCount;
|
||||||
|
|
||||||
|
// Get a temporary IAudioClient for more details
|
||||||
{
|
{
|
||||||
IAudioClient *tmpClient;
|
IAudioClient *tmpClient;
|
||||||
WAVEFORMATEX *mixFormat;
|
WAVEFORMATEX *mixFormat;
|
||||||
|
|
||||||
#ifdef PA_WINRT
|
|
||||||
// Set flow as ActivateAudioInterface depends on it and selects corresponding
|
|
||||||
// direction for the Audio Client
|
|
||||||
wasapiDeviceInfo->flow = (index == 0 ? eRender : eCapture);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Create temp Audio Client instance to query additional details
|
|
||||||
hr = ActivateAudioInterface(wasapiDeviceInfo, NULL, &tmpClient);
|
hr = ActivateAudioInterface(wasapiDeviceInfo, NULL, &tmpClient);
|
||||||
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
||||||
|
|
||||||
|
|
@ -1926,30 +1984,11 @@ static PaError FillDeviceInfo(PaWasapiHostApiRepresentation *paWasapi, void *pEn
|
||||||
#ifdef PA_WINRT
|
#ifdef PA_WINRT
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
// Default device
|
// Set state
|
||||||
if (index == 0)
|
|
||||||
hostApi->info.defaultOutputDevice = hostApi->info.deviceCount;
|
|
||||||
else
|
|
||||||
hostApi->info.defaultInputDevice = hostApi->info.deviceCount;
|
|
||||||
|
|
||||||
// State
|
|
||||||
wasapiDeviceInfo->state = DEVICE_STATE_ACTIVE;
|
wasapiDeviceInfo->state = DEVICE_STATE_ACTIVE;
|
||||||
|
|
||||||
// Default format is always a mix format
|
// Default format (Shared mode) is always a mix format
|
||||||
wasapiDeviceInfo->DefaultFormat = wasapiDeviceInfo->MixFormat;
|
wasapiDeviceInfo->DefaultFormat = wasapiDeviceInfo->MixFormat;
|
||||||
|
|
||||||
// Form-factor
|
|
||||||
wasapiDeviceInfo->formFactor = UnknownFormFactor;
|
|
||||||
|
|
||||||
// Name
|
|
||||||
if ((deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1)) == NULL)
|
|
||||||
{
|
|
||||||
SAFE_RELEASE(tmpClient);
|
|
||||||
result = paInsufficientMemory;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
_snprintf((char *)deviceInfo->name, MAX_STR_LEN - 1, "WASAPI_%s:%d", (index == 0 ? "Output" : "Input"), index);
|
|
||||||
PA_DEBUG(("WASAPI:%d| name[%s]\n", index, deviceInfo->name));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -2049,9 +2088,9 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||||
PaUtilHostApiRepresentation *hostApi = (PaUtilHostApiRepresentation *)paWasapi;
|
PaUtilHostApiRepresentation *hostApi = (PaUtilHostApiRepresentation *)paWasapi;
|
||||||
PaError result = paNoError;
|
PaError result = paNoError;
|
||||||
PaDeviceInfo *deviceInfoArray;
|
PaDeviceInfo *deviceInfoArray;
|
||||||
UINT i;
|
UINT32 i;
|
||||||
WCHAR *defaultRenderer = NULL;
|
WCHAR *defaultRenderId = NULL;
|
||||||
WCHAR *defaultCapturer = NULL;
|
WCHAR *defaultCaptureId = NULL;
|
||||||
#ifndef PA_WINRT
|
#ifndef PA_WINRT
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
IMMDeviceCollection *pEndPoints = NULL;
|
IMMDeviceCollection *pEndPoints = NULL;
|
||||||
|
|
@ -2059,6 +2098,9 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||||
#else
|
#else
|
||||||
void *pEndPoints = NULL;
|
void *pEndPoints = NULL;
|
||||||
IAudioClient *tmpClient;
|
IAudioClient *tmpClient;
|
||||||
|
PaWasapiWinrtDeviceListContext deviceListContext = { 0 };
|
||||||
|
PaWasapiWinrtDeviceInfo defaultRender = { 0 };
|
||||||
|
PaWasapiWinrtDeviceInfo defaultCapture = { 0 };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Make sure device list empty
|
// Make sure device list empty
|
||||||
|
|
@ -2084,7 +2126,7 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hr = IMMDevice_GetId(device, &defaultRenderer);
|
hr = IMMDevice_GetId(device, &defaultRenderId);
|
||||||
IMMDevice_Release(device);
|
IMMDevice_Release(device);
|
||||||
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
||||||
}
|
}
|
||||||
|
|
@ -2099,7 +2141,7 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hr = IMMDevice_GetId(device, &defaultCapturer);
|
hr = IMMDevice_GetId(device, &defaultCaptureId);
|
||||||
IMMDevice_Release(device);
|
IMMDevice_Release(device);
|
||||||
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
||||||
}
|
}
|
||||||
|
|
@ -2113,16 +2155,52 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||||
hr = IMMDeviceCollection_GetCount(pEndPoints, &paWasapi->deviceCount);
|
hr = IMMDeviceCollection_GetCount(pEndPoints, &paWasapi->deviceCount);
|
||||||
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
||||||
#else
|
#else
|
||||||
// Determine number of available devices by activating AudioClient for render and capture data flows
|
WinRT_GetDefaultDeviceId(defaultRender.id, STATIC_ARRAY_SIZE(defaultRender.id) - 1, eRender);
|
||||||
if (SUCCEEDED(ActivateAudioInterface_WINRT(eRender, GetAudioClientIID(), &tmpClient)))
|
defaultRenderId = defaultRender.id;
|
||||||
|
|
||||||
|
WinRT_GetDefaultDeviceId(defaultCapture.id, STATIC_ARRAY_SIZE(defaultCapture.id) - 1, eCapture);
|
||||||
|
defaultCaptureId = defaultCapture.id;
|
||||||
|
|
||||||
|
if (g_DeviceListInfo.render.deviceCount == 0)
|
||||||
{
|
{
|
||||||
paWasapi->deviceCount++;
|
if (SUCCEEDED(WinRT_ActivateAudioInterface(defaultRenderId, GetAudioClientIID(), &tmpClient)))
|
||||||
SAFE_RELEASE(tmpClient);
|
{
|
||||||
|
deviceListContext.devices[paWasapi->deviceCount].info = &defaultRender;
|
||||||
|
deviceListContext.devices[paWasapi->deviceCount].flow = eRender;
|
||||||
|
paWasapi->deviceCount++;
|
||||||
|
|
||||||
|
SAFE_RELEASE(tmpClient);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (SUCCEEDED(ActivateAudioInterface_WINRT(eCapture, GetAudioClientIID(), &tmpClient)))
|
else
|
||||||
{
|
{
|
||||||
paWasapi->deviceCount++;
|
for (i = 0; i < g_DeviceListInfo.render.deviceCount; ++i)
|
||||||
SAFE_RELEASE(tmpClient);
|
{
|
||||||
|
deviceListContext.devices[paWasapi->deviceCount].info = &g_DeviceListInfo.render.devices[i];
|
||||||
|
deviceListContext.devices[paWasapi->deviceCount].flow = eRender;
|
||||||
|
paWasapi->deviceCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_DeviceListInfo.capture.deviceCount == 0)
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(WinRT_ActivateAudioInterface(defaultCaptureId, GetAudioClientIID(), &tmpClient)))
|
||||||
|
{
|
||||||
|
deviceListContext.devices[paWasapi->deviceCount].info = &defaultCapture;
|
||||||
|
deviceListContext.devices[paWasapi->deviceCount].flow = eCapture;
|
||||||
|
paWasapi->deviceCount++;
|
||||||
|
|
||||||
|
SAFE_RELEASE(tmpClient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < g_DeviceListInfo.capture.deviceCount; ++i)
|
||||||
|
{
|
||||||
|
deviceListContext.devices[paWasapi->deviceCount].info = &g_DeviceListInfo.capture.devices[i];
|
||||||
|
deviceListContext.devices[paWasapi->deviceCount].flow = eCapture;
|
||||||
|
paWasapi->deviceCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -2143,8 +2221,12 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||||
|
|
||||||
FillBaseDeviceInfo(deviceInfo, hostApiIndex);
|
FillBaseDeviceInfo(deviceInfo, hostApiIndex);
|
||||||
|
|
||||||
if ((result = FillDeviceInfo(paWasapi, pEndPoints, i, defaultRenderer, defaultCapturer,
|
if ((result = FillDeviceInfo(paWasapi, pEndPoints, i, defaultRenderId, defaultCaptureId,
|
||||||
deviceInfo, &paWasapi->devInfo[i])) != paNoError)
|
deviceInfo, &paWasapi->devInfo[i]
|
||||||
|
#ifdef PA_WINRT
|
||||||
|
, &deviceListContext
|
||||||
|
#endif
|
||||||
|
)) != paNoError)
|
||||||
{
|
{
|
||||||
// Faulty device is made inactive
|
// Faulty device is made inactive
|
||||||
if ((result = FillInactiveDeviceInfo(paWasapi, deviceInfo)) != paNoError)
|
if ((result = FillInactiveDeviceInfo(paWasapi, deviceInfo)) != paNoError)
|
||||||
|
|
@ -2182,8 +2264,8 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||||
done:
|
done:
|
||||||
|
|
||||||
#ifndef PA_WINRT
|
#ifndef PA_WINRT
|
||||||
CoTaskMemFree(defaultRenderer);
|
CoTaskMemFree(defaultRenderId);
|
||||||
CoTaskMemFree(defaultCapturer);
|
CoTaskMemFree(defaultCaptureId);
|
||||||
SAFE_RELEASE(pEndPoints);
|
SAFE_RELEASE(pEndPoints);
|
||||||
SAFE_RELEASE(pEnumerator);
|
SAFE_RELEASE(pEnumerator);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -5346,10 +5428,30 @@ PaError PaWasapi_GetAudioClient(PaStream *pStream, void **pAudioClient, int bOut
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
PaError PaWasapi_SetDefaultInterfaceId( unsigned short *pId, int bOutput )
|
#ifdef PA_WINRT
|
||||||
|
static void CopyNameOrIdString(WCHAR *dst, const UINT32 dstMaxCount, const WCHAR *src)
|
||||||
|
{
|
||||||
|
UINT32 i;
|
||||||
|
|
||||||
|
for (i = 0; i < dstMaxCount; ++i)
|
||||||
|
dst[i] = 0;
|
||||||
|
|
||||||
|
if (src != NULL)
|
||||||
|
{
|
||||||
|
for (i = 0; (src[i] != 0) && (i < dstMaxCount); ++i)
|
||||||
|
dst[i] = src[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------
|
||||||
|
PaError PaWasapiWinrt_SetDefaultDeviceId( const unsigned short *pId, int bOutput )
|
||||||
{
|
{
|
||||||
#ifdef PA_WINRT
|
#ifdef PA_WINRT
|
||||||
int i;
|
INT32 i;
|
||||||
|
PaWasapiWinrtDeviceListRole *role = (bOutput ? &g_DeviceListInfo.render : &g_DeviceListInfo.capture);
|
||||||
|
|
||||||
|
assert(STATIC_ARRAY_SIZE(role->defaultId) == PA_WASAPI_DEVICE_ID_LEN);
|
||||||
|
|
||||||
// Validate Id length
|
// Validate Id length
|
||||||
if (pId != NULL)
|
if (pId != NULL)
|
||||||
|
|
@ -5362,27 +5464,66 @@ PaError PaWasapi_SetDefaultInterfaceId( unsigned short *pId, int bOutput )
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set Id (or reset to all 0 if NULL is provided)
|
// Set Id (or reset to all 0 if NULL is provided)
|
||||||
if (bOutput)
|
CopyNameOrIdString(role->defaultId, STATIC_ARRAY_SIZE(role->defaultId), pId);
|
||||||
|
|
||||||
|
return paNoError;
|
||||||
|
#else
|
||||||
|
return paIncompatibleStreamHostApi;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------
|
||||||
|
PaError PaWasapiWinrt_PopulateDeviceList( const unsigned short **pId, const unsigned short **pName,
|
||||||
|
const PaWasapiDeviceRole *pRole, unsigned int count, int bOutput )
|
||||||
|
{
|
||||||
|
#ifdef PA_WINRT
|
||||||
|
UINT32 i, j;
|
||||||
|
PaWasapiWinrtDeviceListRole *role = (bOutput ? &g_DeviceListInfo.render : &g_DeviceListInfo.capture);
|
||||||
|
|
||||||
|
memset(&role->devices, 0, sizeof(role->devices));
|
||||||
|
role->deviceCount = 0;
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
return paNoError;
|
||||||
|
else
|
||||||
|
if (count > PA_WASAPI_DEVICE_MAX_COUNT)
|
||||||
|
return paBufferTooBig;
|
||||||
|
|
||||||
|
// pName or pRole are optional
|
||||||
|
if (pId == NULL)
|
||||||
|
return paInsufficientMemory;
|
||||||
|
|
||||||
|
// Validate Id and Name lengths
|
||||||
|
for (i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
memset(g_DefaultRenderId, 0, sizeof(g_DefaultRenderId));
|
const unsigned short *id = pId[i];
|
||||||
if (pId != NULL)
|
const unsigned short *name = pName[i];
|
||||||
|
|
||||||
|
for (j = 0; id[j] != 0; ++j)
|
||||||
{
|
{
|
||||||
for (i = 0; (pId[i] != 0) && (i < STATIC_ARRAY_SIZE(g_DefaultRenderId)); ++i)
|
if (j >= PA_WASAPI_DEVICE_ID_LEN)
|
||||||
g_DefaultRenderId[i] = pId[i];
|
return paBufferTooBig;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; name[j] != 0; ++j)
|
||||||
|
{
|
||||||
|
if (j >= PA_WASAPI_DEVICE_NAME_LEN)
|
||||||
|
return paBufferTooBig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Set Id and Name (or reset to all 0 if NULL is provided)
|
||||||
|
for (i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
memset(g_DefaultCaptureId, 0, sizeof(g_DefaultCaptureId));
|
CopyNameOrIdString(role->devices[i].id, STATIC_ARRAY_SIZE(role->devices[i].id), pId[i]);
|
||||||
if (pId != NULL)
|
CopyNameOrIdString(role->devices[i].name, STATIC_ARRAY_SIZE(role->devices[i].name), pName[i]);
|
||||||
{
|
role->devices[i].formFactor = (pRole != NULL ? (EndpointFormFactor)pRole[i] : UnknownFormFactor);
|
||||||
for (i = 0; (pId[i] != 0) && (i < STATIC_ARRAY_SIZE(g_DefaultCaptureId)); ++i)
|
|
||||||
g_DefaultCaptureId[i] = pId[i];
|
// Count device if it has at least the Id
|
||||||
}
|
role->deviceCount += (role->devices[i].id[0] != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return paNoError;
|
return paNoError;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
return paIncompatibleStreamHostApi;
|
return paIncompatibleStreamHostApi;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue