wasapi: Improved loopback implementation by avoiding excessive memory allocations inside the CreateDeviceList(), cleaned up comment, added export for PaWasapi_IsLoopback into .def.
This commit is contained in:
parent
7e667532a4
commit
605fc89d57
|
@ -60,7 +60,8 @@ PaUtil_SetDebugPrintFunction @55
|
||||||
@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapiWinrt_SetDefaultDeviceId @67
|
@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapiWinrt_SetDefaultDeviceId @67
|
||||||
@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapiWinrt_PopulateDeviceList @69
|
@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapiWinrt_PopulateDeviceList @69
|
||||||
@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetIMMDevice @70
|
@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetIMMDevice @70
|
||||||
@DEF_EXCLUDE_WMME_SYMBOLS@PaWinMME_GetStreamInputHandleCount @71
|
@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_IsLoopback @71
|
||||||
@DEF_EXCLUDE_WMME_SYMBOLS@PaWinMME_GetStreamInputHandle @72
|
@DEF_EXCLUDE_WMME_SYMBOLS@PaWinMME_GetStreamInputHandleCount @72
|
||||||
@DEF_EXCLUDE_WMME_SYMBOLS@PaWinMME_GetStreamOutputHandleCount @73
|
@DEF_EXCLUDE_WMME_SYMBOLS@PaWinMME_GetStreamInputHandle @73
|
||||||
@DEF_EXCLUDE_WMME_SYMBOLS@PaWinMME_GetStreamOutputHandle @74
|
@DEF_EXCLUDE_WMME_SYMBOLS@PaWinMME_GetStreamOutputHandleCount @74
|
||||||
|
@DEF_EXCLUDE_WMME_SYMBOLS@PaWinMME_GetStreamOutputHandle @75
|
||||||
|
|
|
@ -437,7 +437,7 @@ int PaWasapi_GetDeviceMixFormat( void *pFormat, unsigned int formatSize, PaDevic
|
||||||
int/*PaWasapiDeviceRole*/ PaWasapi_GetDeviceRole( PaDeviceIndex device );
|
int/*PaWasapiDeviceRole*/ PaWasapi_GetDeviceRole( PaDeviceIndex device );
|
||||||
|
|
||||||
|
|
||||||
/** Get device IMMDevice pointer
|
/** Get device IMMDevice pointer.
|
||||||
|
|
||||||
@param device Device index.
|
@param device Device index.
|
||||||
@param pAudioClient Pointer to pointer of IMMDevice.
|
@param pAudioClient Pointer to pointer of IMMDevice.
|
||||||
|
@ -447,6 +447,20 @@ int/*PaWasapiDeviceRole*/ PaWasapi_GetDeviceRole( PaDeviceIndex device );
|
||||||
PaError PaWasapi_GetIMMDevice( PaDeviceIndex device, void **pIMMDevice );
|
PaError PaWasapi_GetIMMDevice( PaDeviceIndex device, void **pIMMDevice );
|
||||||
|
|
||||||
|
|
||||||
|
/** Get device loopback state:
|
||||||
|
|
||||||
|
0 - Not loopback,
|
||||||
|
1 - Loopback,
|
||||||
|
negative - PaErrorCode.
|
||||||
|
|
||||||
|
@param device Device index.
|
||||||
|
|
||||||
|
@return Non-negative value indicating loopback state or, a PaErrorCode (which is always negative)
|
||||||
|
if PortAudio is not initialized or an error is encountered.
|
||||||
|
*/
|
||||||
|
int PaWasapi_IsLoopback( PaDeviceIndex device );
|
||||||
|
|
||||||
|
|
||||||
/** Boost thread priority of calling thread (MMCSS).
|
/** Boost thread priority of calling thread (MMCSS).
|
||||||
|
|
||||||
Use it for Blocking Interface only inside the thread which makes calls to Pa_WriteStream/Pa_ReadStream.
|
Use it for Blocking Interface only inside the thread which makes calls to Pa_WriteStream/Pa_ReadStream.
|
||||||
|
@ -605,15 +619,6 @@ PaError PaWasapiWinrt_PopulateDeviceList( const unsigned short **pId, const unsi
|
||||||
const PaWasapiDeviceRole *pRole, unsigned int count, int bOutput );
|
const PaWasapiDeviceRole *pRole, unsigned int count, int bOutput );
|
||||||
|
|
||||||
|
|
||||||
/** Returns device loopback indicator.
|
|
||||||
|
|
||||||
@param nDevice device index.
|
|
||||||
|
|
||||||
@return 0 = Not loopback, 1 = loopback, < 0 = PaErrorCode
|
|
||||||
if PortAudio is not initialized or an error is encountered.
|
|
||||||
*/
|
|
||||||
int PaWasapi_IsLoopback( PaDeviceIndex nDevice );
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
IMPORTANT:
|
IMPORTANT:
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,8 @@ PaWasapi_SetStreamStateHandler @68
|
||||||
PaWasapiWinrt_SetDefaultDeviceId @67
|
PaWasapiWinrt_SetDefaultDeviceId @67
|
||||||
PaWasapiWinrt_PopulateDeviceList @69
|
PaWasapiWinrt_PopulateDeviceList @69
|
||||||
PaWasapi_GetIMMDevice @70
|
PaWasapi_GetIMMDevice @70
|
||||||
PaWinMME_GetStreamInputHandleCount @71
|
PaWasapi_IsLoopback @71
|
||||||
PaWinMME_GetStreamInputHandle @72
|
PaWinMME_GetStreamInputHandleCount @72
|
||||||
PaWinMME_GetStreamOutputHandleCount @73
|
PaWinMME_GetStreamInputHandle @73
|
||||||
PaWinMME_GetStreamOutputHandle @74
|
PaWinMME_GetStreamOutputHandleCount @74
|
||||||
|
PaWinMME_GetStreamOutputHandle @75
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Portable Audio I/O Library WASAPI implementation
|
* Portable Audio I/O Library WASAPI implementation
|
||||||
* Copyright (c) 2006-2010 David Viens
|
* Copyright (c) 2006-2010 David Viens
|
||||||
* Copyright (c) 2010-2019 Dmitry Kostjuchenko
|
* Copyright (c) 2010-2022 Dmitry Kostjuchenko
|
||||||
*
|
*
|
||||||
* Based on the Open Source API proposed by Ross Bencina
|
* Based on the Open Source API proposed by Ross Bencina
|
||||||
* Copyright (c) 1999-2019 Ross Bencina, Phil Burk
|
* Copyright (c) 1999-2019 Ross Bencina, Phil Burk
|
||||||
|
@ -367,6 +367,7 @@ enum { WASAPI_PACKETS_PER_INPUT_BUFFER = 6 };
|
||||||
|
|
||||||
#define SAFE_CLOSE(h) if ((h) != NULL) { CloseHandle((h)); (h) = NULL; }
|
#define SAFE_CLOSE(h) if ((h) != NULL) { CloseHandle((h)); (h) = NULL; }
|
||||||
#define SAFE_RELEASE(punk) if ((punk) != NULL) { (punk)->lpVtbl->Release((punk)); (punk) = NULL; }
|
#define SAFE_RELEASE(punk) if ((punk) != NULL) { (punk)->lpVtbl->Release((punk)); (punk) = NULL; }
|
||||||
|
#define SAFE_ADDREF(punk) if ((punk) != NULL) { (punk)->lpVtbl->AddRef((punk)); }
|
||||||
|
|
||||||
// Mixer function
|
// Mixer function
|
||||||
typedef void (*MixMonoToStereoF) (void *__to, const void *__from, UINT32 count);
|
typedef void (*MixMonoToStereoF) (void *__to, const void *__from, UINT32 count);
|
||||||
|
@ -479,14 +480,14 @@ typedef struct PaWasapiDeviceInfo
|
||||||
// Form-factor
|
// Form-factor
|
||||||
EndpointFormFactor formFactor;
|
EndpointFormFactor formFactor;
|
||||||
|
|
||||||
// Loopback indicator
|
// Loopback state (TRUE if device acts as loopback)
|
||||||
BOOL loopBack;
|
BOOL loopBack;
|
||||||
}
|
}
|
||||||
PaWasapiDeviceInfo;
|
PaWasapiDeviceInfo;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
/* PaWasapiHostApiRepresentation - host api datastructure specific to this implementation */
|
/* PaWasapiHostApiRepresentation - host api datastructure specific to this implementation */
|
||||||
typedef struct
|
typedef struct PaWasapiHostApiRepresentation
|
||||||
{
|
{
|
||||||
PaUtilHostApiRepresentation inheritedHostApiRep;
|
PaUtilHostApiRepresentation inheritedHostApiRep;
|
||||||
PaUtilStreamInterface callbackStreamInterface;
|
PaUtilStreamInterface callbackStreamInterface;
|
||||||
|
@ -2074,22 +2075,21 @@ error:
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
static PaDeviceInfo *AllocateDeviceListMemory(PaWasapiHostApiRepresentation *paWasapi)
|
static PaDeviceInfo *AllocateDeviceListMemory(PaWasapiHostApiRepresentation *paWasapi, UINT32 deviceCount)
|
||||||
{
|
{
|
||||||
PaUtilHostApiRepresentation *hostApi = (PaUtilHostApiRepresentation *)paWasapi;
|
PaUtilHostApiRepresentation *hostApi = (PaUtilHostApiRepresentation *)paWasapi;
|
||||||
PaDeviceInfo *deviceInfoArray = NULL;
|
PaDeviceInfo *deviceInfoArray = NULL;
|
||||||
|
|
||||||
if ((paWasapi->devInfo = (PaWasapiDeviceInfo *)PaUtil_GroupAllocateMemory(paWasapi->allocations,
|
if ((paWasapi->devInfo = (PaWasapiDeviceInfo *)PaUtil_GroupAllocateMemory(paWasapi->allocations,
|
||||||
sizeof(PaWasapiDeviceInfo) * paWasapi->deviceCount)) == NULL)
|
sizeof(PaWasapiDeviceInfo) * deviceCount)) == NULL)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset(paWasapi->devInfo, 0, sizeof(PaWasapiDeviceInfo) * paWasapi->deviceCount);
|
memset(paWasapi->devInfo, 0, sizeof(PaWasapiDeviceInfo) * deviceCount);
|
||||||
|
|
||||||
if (paWasapi->deviceCount != 0)
|
if (deviceCount != 0)
|
||||||
{
|
{
|
||||||
UINT32 i;
|
UINT32 i;
|
||||||
UINT32 deviceCount = paWasapi->deviceCount;
|
|
||||||
#if defined(PA_WASAPI_MAX_CONST_DEVICE_COUNT) && (PA_WASAPI_MAX_CONST_DEVICE_COUNT > 0)
|
#if defined(PA_WASAPI_MAX_CONST_DEVICE_COUNT) && (PA_WASAPI_MAX_CONST_DEVICE_COUNT > 0)
|
||||||
if (deviceCount < PA_WASAPI_MAX_CONST_DEVICE_COUNT)
|
if (deviceCount < PA_WASAPI_MAX_CONST_DEVICE_COUNT)
|
||||||
deviceCount = PA_WASAPI_MAX_CONST_DEVICE_COUNT;
|
deviceCount = PA_WASAPI_MAX_CONST_DEVICE_COUNT;
|
||||||
|
@ -2116,57 +2116,91 @@ static PaDeviceInfo *AllocateDeviceListMemory(PaWasapiHostApiRepresentation *paW
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
static PaDeviceInfo *AddLoopbacksToDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaDeviceInfo *deviceInfoArray, INT32 loopbackindex)
|
#ifndef PA_WINRT
|
||||||
|
static UINT32 GetDeviceListDeviceCount(IMMDeviceCollection *pEndPoints, EDataFlow filterFlow)
|
||||||
{
|
{
|
||||||
PaUtilHostApiRepresentation *hostApi = (PaUtilHostApiRepresentation *)paWasapi;
|
HRESULT hr;
|
||||||
PaDeviceInfo *newDeviceInfoArray = NULL;
|
UINT32 deviceCount;
|
||||||
UINT32 deviceCount = paWasapi->deviceCount;
|
IMMDevice *device;
|
||||||
PaWasapiDeviceInfo *newDevInfo = NULL;
|
IMMEndpoint *endpoint;
|
||||||
|
EDataFlow flow;
|
||||||
|
UINT32 ret = 0;
|
||||||
|
|
||||||
// deviceInfoArray
|
hr = IMMDeviceCollection_GetCount(pEndPoints, &deviceCount);
|
||||||
if ((newDeviceInfoArray = (PaDeviceInfo *)PaUtil_GroupAllocateMemory(paWasapi->allocations,
|
IF_FAILED_JUMP(hr, error);
|
||||||
sizeof(PaDeviceInfo) * (deviceCount + 1))) == NULL)
|
|
||||||
|
for (UINT32 i = 0; i < deviceCount; ++i)
|
||||||
{
|
{
|
||||||
return NULL;
|
hr = IMMDeviceCollection_Item((IMMDeviceCollection *)pEndPoints, i, &device);
|
||||||
}
|
IF_FAILED_JUMP(hr, error);
|
||||||
memcpy(newDeviceInfoArray, deviceInfoArray, sizeof(PaDeviceInfo) * deviceCount);
|
|
||||||
memcpy(newDeviceInfoArray + deviceCount, &deviceInfoArray[loopbackindex], sizeof(PaDeviceInfo));
|
|
||||||
|
|
||||||
// paWasapi->devInfo
|
if (SUCCEEDED(hr = IMMDevice_QueryInterface(device, &pa_IID_IMMEndpoint, (void **)&endpoint)))
|
||||||
if ((newDevInfo = (PaWasapiDeviceInfo *)PaUtil_GroupAllocateMemory(paWasapi->allocations,
|
{
|
||||||
sizeof(PaWasapiDeviceInfo) * (deviceCount + 1))) == NULL)
|
if (SUCCEEDED(hr = IMMEndpoint_GetDataFlow(endpoint, &flow)))
|
||||||
{
|
ret += (flow == filterFlow);
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memcpy(newDevInfo, paWasapi->devInfo, sizeof(PaWasapiDeviceInfo) * deviceCount);
|
|
||||||
memcpy(newDevInfo + deviceCount, &paWasapi->devInfo[loopbackindex], sizeof(paWasapi->devInfo));
|
|
||||||
newDevInfo[deviceCount].loopBack = 1;
|
|
||||||
if ((paWasapi->devInfo = (PaWasapiDeviceInfo *)PaUtil_GroupAllocateMemory(paWasapi->allocations,
|
|
||||||
sizeof(PaWasapiDeviceInfo) * (deviceCount + 1))) == NULL)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memcpy(paWasapi->devInfo, newDevInfo, sizeof(PaWasapiDeviceInfo) * (deviceCount + 1));
|
|
||||||
|
|
||||||
// loopback attributes
|
SAFE_RELEASE(endpoint);
|
||||||
char *deviceName;
|
}
|
||||||
PaDeviceInfo *deviceInfo = &newDeviceInfoArray[deviceCount];
|
|
||||||
deviceName = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, PA_WASAPI_DEVICE_NAME_LEN +1);
|
SAFE_RELEASE(device);
|
||||||
if (deviceName == NULL)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
_snprintf(deviceName, PA_WASAPI_DEVICE_NAME_LEN -1, "%s (loopback)", deviceInfo->name);
|
|
||||||
deviceInfo->name = deviceName;
|
|
||||||
|
|
||||||
deviceInfo->maxInputChannels = deviceInfo->maxOutputChannels;
|
return ret;
|
||||||
deviceInfo->defaultHighInputLatency = deviceInfo->defaultHighOutputLatency;
|
|
||||||
deviceInfo->defaultLowInputLatency = deviceInfo->defaultLowOutputLatency;
|
|
||||||
deviceInfo->maxOutputChannels = 0;
|
|
||||||
deviceInfo->defaultHighOutputLatency = 0;
|
|
||||||
deviceInfo->defaultLowOutputLatency = 0;
|
|
||||||
|
|
||||||
return newDeviceInfoArray;
|
error:
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static UINT32 GetDeviceListDeviceCount(const PaWasapiHostApiRepresentation *paWasapi,
|
||||||
|
const PaWasapiWinrtDeviceListContext *deviceListContext, EDataFlow filterFlow)
|
||||||
|
{
|
||||||
|
UINT32 i, ret = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < paWasapi->deviceCount; ++i)
|
||||||
|
ret += (deviceListContext->devices[i].flow == filterFlow);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------
|
||||||
|
static BOOL FillLooopbackDeviceInfo(PaWasapiHostApiRepresentation *paWasapi, PaDeviceInfo *loopbackDeviceInfo,
|
||||||
|
PaWasapiDeviceInfo *loopbackWasapiInfo, const PaDeviceInfo *deviceInfo, const PaWasapiDeviceInfo *wasapiInfo)
|
||||||
|
{
|
||||||
|
// Loopback device name identificator
|
||||||
|
// note: Some projects depend on loopback device detection by device name, do not change!
|
||||||
|
#define PA_WASAPI_LOOPBACK_NAME_IDENTIFICATOR "[Loopback]"
|
||||||
|
|
||||||
|
memcpy(loopbackDeviceInfo, deviceInfo, sizeof(*loopbackDeviceInfo));
|
||||||
|
memcpy(loopbackWasapiInfo, wasapiInfo, sizeof(*loopbackWasapiInfo));
|
||||||
|
|
||||||
|
// Append loopback device name identificator to the device name to provide possibility to find
|
||||||
|
// loopback device by its name for some external projects
|
||||||
|
loopbackDeviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, PA_WASAPI_DEVICE_NAME_LEN + 1);
|
||||||
|
if (loopbackDeviceInfo->name == NULL)
|
||||||
|
return FALSE;
|
||||||
|
_snprintf((char *)loopbackDeviceInfo->name, PA_WASAPI_DEVICE_NAME_LEN - 1,
|
||||||
|
"%s " PA_WASAPI_LOOPBACK_NAME_IDENTIFICATOR, deviceInfo->name);
|
||||||
|
|
||||||
|
// Acquire ref to the device as it is already referenced as render (output) device
|
||||||
|
// to avoid duplicate release in ReleaseWasapiDeviceInfoList()
|
||||||
|
#ifndef PA_WINRT
|
||||||
|
SAFE_ADDREF(loopbackWasapiInfo->device);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Mark as loopback device
|
||||||
|
loopbackWasapiInfo->loopBack = TRUE;
|
||||||
|
|
||||||
|
// Input is the reverse of Output
|
||||||
|
loopbackDeviceInfo->maxInputChannels = deviceInfo->maxOutputChannels;
|
||||||
|
loopbackDeviceInfo->defaultHighInputLatency = deviceInfo->defaultHighOutputLatency;
|
||||||
|
loopbackDeviceInfo->defaultLowInputLatency = deviceInfo->defaultLowOutputLatency;
|
||||||
|
loopbackDeviceInfo->maxOutputChannels = 0;
|
||||||
|
loopbackDeviceInfo->defaultHighOutputLatency = 0;
|
||||||
|
loopbackDeviceInfo->defaultLowOutputLatency = 0;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
|
@ -2175,7 +2209,7 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||||
PaUtilHostApiRepresentation *hostApi = (PaUtilHostApiRepresentation *)paWasapi;
|
PaUtilHostApiRepresentation *hostApi = (PaUtilHostApiRepresentation *)paWasapi;
|
||||||
PaError result = paNoError;
|
PaError result = paNoError;
|
||||||
PaDeviceInfo *deviceInfoArray = NULL;
|
PaDeviceInfo *deviceInfoArray = NULL;
|
||||||
UINT32 i;
|
UINT32 i, j, loopbacks;
|
||||||
WCHAR *defaultRenderId = NULL;
|
WCHAR *defaultRenderId = NULL;
|
||||||
WCHAR *defaultCaptureId = NULL;
|
WCHAR *defaultCaptureId = NULL;
|
||||||
#ifndef PA_WINRT
|
#ifndef PA_WINRT
|
||||||
|
@ -2241,6 +2275,9 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||||
// Get device count
|
// Get device count
|
||||||
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);
|
||||||
|
|
||||||
|
// Get loopback device count (e.g. all renders)
|
||||||
|
loopbacks = GetDeviceListDeviceCount(pEndPoints, eRender);
|
||||||
#else
|
#else
|
||||||
WinRT_GetDefaultDeviceId(defaultRender.id, STATIC_ARRAY_SIZE(defaultRender.id) - 1, eRender);
|
WinRT_GetDefaultDeviceId(defaultRender.id, STATIC_ARRAY_SIZE(defaultRender.id) - 1, eRender);
|
||||||
defaultRenderId = defaultRender.id;
|
defaultRenderId = defaultRender.id;
|
||||||
|
@ -2289,19 +2326,24 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||||
paWasapi->deviceCount++;
|
paWasapi->deviceCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get loopback device count (e.g. all renders)
|
||||||
|
loopbacks = GetDeviceListDeviceCount(paWasapi, &deviceListContext, eRender);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Allocate memory for the device list
|
// Allocate memory for the device list
|
||||||
if ((paWasapi->deviceCount != 0) && ((deviceInfoArray = AllocateDeviceListMemory(paWasapi)) == NULL))
|
if ((paWasapi->deviceCount != 0) &&
|
||||||
|
((deviceInfoArray = AllocateDeviceListMemory(paWasapi, paWasapi->deviceCount + loopbacks)) == NULL))
|
||||||
{
|
{
|
||||||
result = paInsufficientMemory;
|
result = paInsufficientMemory;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill WASAPI device info
|
// Fill WASAPI device info
|
||||||
for (i = 0; i < paWasapi->deviceCount; ++i)
|
for (i = 0, j = 0; i < paWasapi->deviceCount; ++i)
|
||||||
{
|
{
|
||||||
PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
|
PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
|
||||||
|
PaWasapiDeviceInfo *wasapiInfo = &paWasapi->devInfo[i];
|
||||||
|
|
||||||
PA_DEBUG(("WASAPI: device idx: %02d\n", i));
|
PA_DEBUG(("WASAPI: device idx: %02d\n", i));
|
||||||
PA_DEBUG(("WASAPI: ---------------\n"));
|
PA_DEBUG(("WASAPI: ---------------\n"));
|
||||||
|
@ -2309,7 +2351,7 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||||
FillBaseDeviceInfo(deviceInfo, hostApiIndex);
|
FillBaseDeviceInfo(deviceInfo, hostApiIndex);
|
||||||
|
|
||||||
if ((result = FillDeviceInfo(paWasapi, pEndPoints, i, defaultRenderId, defaultCaptureId,
|
if ((result = FillDeviceInfo(paWasapi, pEndPoints, i, defaultRenderId, defaultCaptureId,
|
||||||
deviceInfo, &paWasapi->devInfo[i]
|
deviceInfo, wasapiInfo
|
||||||
#ifdef PA_WINRT
|
#ifdef PA_WINRT
|
||||||
, &deviceListContext
|
, &deviceListContext
|
||||||
#endif
|
#endif
|
||||||
|
@ -2322,35 +2364,28 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||||
|
|
||||||
hostApi->deviceInfos[i] = deviceInfo;
|
hostApi->deviceInfos[i] = deviceInfo;
|
||||||
++hostApi->info.deviceCount;
|
++hostApi->info.deviceCount;
|
||||||
}
|
|
||||||
|
|
||||||
// check for loopbacks
|
// Add loopback device for the render device
|
||||||
UINT32 initialDevices = paWasapi->deviceCount;
|
if (paWasapi->devInfo[i].flow == eRender)
|
||||||
for (i = 0; i < initialDevices; ++i) {
|
{
|
||||||
if (paWasapi->devInfo[i].flow == eRender) {
|
// Add loopback device to the end of the device list
|
||||||
// need to add a loopback for this render device
|
UINT32 loopbackIndex = paWasapi->deviceCount + j++;
|
||||||
if ((deviceInfoArray = AddLoopbacksToDeviceList(paWasapi, deviceInfoArray, i)) == NULL)
|
PaDeviceInfo *loopbackDeviceInfo = &deviceInfoArray[loopbackIndex];
|
||||||
|
PaWasapiDeviceInfo *loopbackWasapiInfo = &paWasapi->devInfo[loopbackIndex];
|
||||||
|
|
||||||
|
if (!FillLooopbackDeviceInfo(paWasapi, loopbackDeviceInfo, loopbackWasapiInfo, deviceInfo, wasapiInfo))
|
||||||
{
|
{
|
||||||
result = paInsufficientMemory;
|
result = paInsufficientMemory;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
paWasapi->devInfo[paWasapi->deviceCount].loopBack = TRUE;
|
|
||||||
|
hostApi->deviceInfos[loopbackIndex] = loopbackDeviceInfo;
|
||||||
++hostApi->info.deviceCount;
|
++hostApi->info.deviceCount;
|
||||||
++paWasapi->deviceCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// all loopbacks found, so write new devicelist to hostApi->deviceInfos
|
// Resize device list to accomodate inserted loopback devices
|
||||||
if ((hostApi->deviceInfos = (PaDeviceInfo **)PaUtil_GroupAllocateMemory(paWasapi->allocations,
|
paWasapi->deviceCount += loopbacks;
|
||||||
sizeof(PaDeviceInfo *) * paWasapi->deviceCount)) == NULL)
|
|
||||||
{
|
|
||||||
result = paInsufficientMemory;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
for (i = 0; i < paWasapi->deviceCount; ++i)
|
|
||||||
{
|
|
||||||
hostApi->deviceInfos[i] = &deviceInfoArray[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill the remaining slots with inactive device info
|
// Fill the remaining slots with inactive device info
|
||||||
#if defined(PA_WASAPI_MAX_CONST_DEVICE_COUNT) && (PA_WASAPI_MAX_CONST_DEVICE_COUNT > 0)
|
#if defined(PA_WASAPI_MAX_CONST_DEVICE_COUNT) && (PA_WASAPI_MAX_CONST_DEVICE_COUNT > 0)
|
||||||
|
@ -2374,7 +2409,7 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||||
// Clear any non-fatal errors
|
// Clear any non-fatal errors
|
||||||
result = paNoError;
|
result = paNoError;
|
||||||
|
|
||||||
PRINT(("WASAPI: device list ok - found %d devices\n", paWasapi->deviceCount));
|
PRINT(("WASAPI: device list ok - found %d devices, %d loopbacks\n", paWasapi->deviceCount, loopbacks));
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
||||||
|
@ -2725,7 +2760,8 @@ PaError PaWasapi_GetIMMDevice( PaDeviceIndex device, void **pIMMDevice )
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int PaWasapi_IsLoopback( PaDeviceIndex nDevice )
|
// ------------------------------------------------------------------------------------------
|
||||||
|
int PaWasapi_IsLoopback( PaDeviceIndex device )
|
||||||
{
|
{
|
||||||
PaError ret;
|
PaError ret;
|
||||||
PaDeviceIndex index;
|
PaDeviceIndex index;
|
||||||
|
@ -2736,7 +2772,7 @@ int PaWasapi_IsLoopback( PaDeviceIndex nDevice )
|
||||||
return paNotInitialized;
|
return paNotInitialized;
|
||||||
|
|
||||||
// Get device index
|
// Get device index
|
||||||
ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);
|
ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, device, &paWasapi->inheritedHostApiRep);
|
||||||
if (ret != paNoError)
|
if (ret != paNoError)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -3970,8 +4006,12 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
(stream->in.shareMode == AUDCLNT_SHAREMODE_SHARED) &&
|
(stream->in.shareMode == AUDCLNT_SHAREMODE_SHARED) &&
|
||||||
((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiAutoConvert)))
|
((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiAutoConvert)))
|
||||||
stream->in.streamFlags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY);
|
stream->in.streamFlags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY);
|
||||||
|
|
||||||
|
// Loopback device is a real output device, so we open stream with AUDCLNT_STREAMFLAGS_LOOPBACK
|
||||||
|
// flag to make it work as input device
|
||||||
if (info->loopBack)
|
if (info->loopBack)
|
||||||
stream->in.streamFlags |= AUDCLNT_STREAMFLAGS_LOOPBACK;
|
stream->in.streamFlags |= AUDCLNT_STREAMFLAGS_LOOPBACK;
|
||||||
|
|
||||||
// Fill parameters for Audio Client creation
|
// Fill parameters for Audio Client creation
|
||||||
stream->in.params.device_info = info;
|
stream->in.params.device_info = info;
|
||||||
stream->in.params.stream_params = (*inputParameters);
|
stream->in.params.stream_params = (*inputParameters);
|
||||||
|
|
Loading…
Reference in New Issue