mirror of
https://github.com/cookiengineer/audacity
synced 2025-12-20 15:41:18 +01:00
Recreate and apply the WASAPI loopback patch
This commit is contained in:
@@ -449,6 +449,9 @@ typedef struct PaWasapiDeviceInfo
|
||||
|
||||
// Formfactor
|
||||
EndpointFormFactor formFactor;
|
||||
|
||||
// Loopback indicator
|
||||
int loopBack;
|
||||
}
|
||||
PaWasapiDeviceInfo;
|
||||
|
||||
@@ -1674,6 +1677,8 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||
IMMDeviceEnumerator *pEnumerator = NULL;
|
||||
#endif
|
||||
IAudioClient *tmpClient;
|
||||
UINT renderCount;
|
||||
INT devIndex;
|
||||
|
||||
// Make sure device list empty
|
||||
if ((paWasapi->deviceCount != 0) || (hostApi->info.deviceCount != 0))
|
||||
@@ -1738,6 +1743,19 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||
}
|
||||
}
|
||||
|
||||
hr = IMMDeviceEnumerator_EnumAudioEndpoints(pEnumerator, eRender, DEVICE_STATE_ACTIVE, &pEndPoints);
|
||||
// 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);
|
||||
|
||||
hr = IMMDeviceCollection_GetCount(pEndPoints, &renderCount);
|
||||
// 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);
|
||||
|
||||
SAFE_RELEASE(pEndPoints);
|
||||
pEndPoints = NULL;
|
||||
|
||||
hr = IMMDeviceEnumerator_EnumAudioEndpoints(pEnumerator, eAll, DEVICE_STATE_ACTIVE, &pEndPoints);
|
||||
// We need to set the result to a value otherwise we will return paNoError
|
||||
// [IF_FAILED_JUMP(hResult, error);]
|
||||
@@ -1748,6 +1766,7 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||
// [IF_FAILED_JUMP(hResult, error);]
|
||||
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
||||
|
||||
paWasapi->deviceCount += renderCount;
|
||||
#else
|
||||
// Determine number of available devices by activating AudioClient for render and capture data flows
|
||||
if (SUCCEEDED(ActivateAudioInterface_WINRT(eRender, GetAudioClientIID(), &tmpClient)))
|
||||
@@ -1797,7 +1816,7 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||
}
|
||||
memset(deviceInfoArray, 0, sizeof(PaDeviceInfo) * deviceCount);
|
||||
|
||||
for (i = 0; i < paWasapi->deviceCount; ++i)
|
||||
for (devIndex = 0, i = 0; i < paWasapi->deviceCount; ++i, ++devIndex)
|
||||
{
|
||||
PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
|
||||
deviceInfo->structVersion = 2;
|
||||
@@ -1807,7 +1826,7 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||
PA_DEBUG(("WASAPI: ---------------\n"));
|
||||
|
||||
#ifndef PA_WINRT
|
||||
hr = IMMDeviceCollection_Item(pEndPoints, i, &paWasapi->devInfo[i].device);
|
||||
hr = IMMDeviceCollection_Item(pEndPoints, devIndex, &paWasapi->devInfo[i].device);
|
||||
// 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);
|
||||
@@ -2039,6 +2058,42 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
|
||||
|
||||
hostApi->deviceInfos[i] = deviceInfo;
|
||||
++hostApi->info.deviceCount;
|
||||
|
||||
if (paWasapi->devInfo[i].flow == eRender)
|
||||
{
|
||||
char *deviceName;
|
||||
|
||||
memcpy(&deviceInfoArray[i + 1], deviceInfo, sizeof(*deviceInfo));
|
||||
memcpy(&paWasapi->devInfo[i + 1], &paWasapi->devInfo[i], sizeof(*paWasapi->devInfo));
|
||||
|
||||
i++;
|
||||
paWasapi->devInfo[i].loopBack = 1;
|
||||
|
||||
deviceInfo = &deviceInfoArray[i];
|
||||
|
||||
deviceInfo->maxInputChannels = deviceInfo->maxOutputChannels;
|
||||
deviceInfo->defaultHighInputLatency = deviceInfo->defaultHighOutputLatency;
|
||||
deviceInfo->defaultLowInputLatency = deviceInfo->defaultLowOutputLatency;
|
||||
deviceInfo->maxOutputChannels = 0;
|
||||
deviceInfo->defaultHighOutputLatency = 0;
|
||||
deviceInfo->defaultLowOutputLatency = 0;
|
||||
PA_DEBUG(("WASAPI:%d| def.SR[%d] max.CH[%d] latency{hi[%f] lo[%f]}\n", i, (UINT32)deviceInfo->defaultSampleRate,
|
||||
deviceInfo->maxInputChannels, (float)deviceInfo->defaultHighInputLatency, (float)deviceInfo->defaultLowInputLatency));
|
||||
|
||||
IMMDevice_AddRef(paWasapi->devInfo[i].device);
|
||||
|
||||
deviceName = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1);
|
||||
if (deviceName == NULL)
|
||||
{
|
||||
result = paInsufficientMemory;
|
||||
goto error;
|
||||
}
|
||||
_snprintf(deviceName, MAX_STR_LEN-1, "%s (loopback)", deviceInfo->name);
|
||||
deviceInfo->name = deviceName;
|
||||
|
||||
hostApi->deviceInfos[i] = deviceInfo;
|
||||
++hostApi->info.deviceCount;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(PA_WASAPI_MAX_CONST_DEVICE_COUNT) && (PA_WASAPI_MAX_CONST_DEVICE_COUNT > 0)
|
||||
@@ -2392,6 +2447,29 @@ int PaWasapi_GetDeviceRole( PaDeviceIndex device )
|
||||
return paWasapi->devInfo[ index ].formFactor;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
int PaWasapi_IsLoopback( PaDeviceIndex nDevice )
|
||||
{
|
||||
PaError ret;
|
||||
PaDeviceIndex index;
|
||||
|
||||
// Get API
|
||||
PaWasapiHostApiRepresentation *paWasapi = _GetHostApi(&ret);
|
||||
if (paWasapi == NULL)
|
||||
return paNotInitialized;
|
||||
|
||||
// Get device index
|
||||
ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);
|
||||
if (ret != paNoError)
|
||||
return ret;
|
||||
|
||||
// Validate index
|
||||
if ((UINT32)index >= paWasapi->deviceCount)
|
||||
return paInvalidDevice;
|
||||
|
||||
return paWasapi->devInfo[ index ].loopBack;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *pInput, unsigned int *pOutput )
|
||||
{
|
||||
@@ -3055,7 +3133,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
|
||||
if ((params->channelCount == 1) && (pSub->wavex.Format.nChannels == 2))
|
||||
{
|
||||
// select mixer
|
||||
pSub->monoMixer = GetMonoToStereoMixer(&pSub->wavex, (pInfo->flow == eRender ? MIX_DIR__1TO2 : MIX_DIR__2TO1_L));
|
||||
pSub->monoMixer = GetMonoToStereoMixer(&pSub->wavex, (output ? MIX_DIR__1TO2 : MIX_DIR__2TO1_L));
|
||||
if (pSub->monoMixer == NULL)
|
||||
{
|
||||
(*pa_error) = paInvalidChannelCount;
|
||||
@@ -3618,6 +3696,9 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||
((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiAutoConvert)))
|
||||
stream->in.streamFlags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY);
|
||||
|
||||
if (info->flow == eRender)
|
||||
stream->in.streamFlags |= AUDCLNT_STREAMFLAGS_LOOPBACK;
|
||||
|
||||
// Fill parameters for Audio Client creation
|
||||
stream->in.params.device_info = info;
|
||||
stream->in.params.stream_params = (*inputParameters);
|
||||
|
||||
Reference in New Issue
Block a user