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:
dmitrykos 2022-02-04 23:44:06 +02:00
parent 7e667532a4
commit 605fc89d57
4 changed files with 143 additions and 96 deletions

View File

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

View File

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

View File

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

View File

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