1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
diff --git a/lib-src/portaudio-v19/include/pa_win_wasapi.h b/lib-src/portaudio-v19/include/pa_win_wasapi.h
index 1087157..e52d0a7 100644
--- a/lib-src/portaudio-v19/include/pa_win_wasapi.h
+++ b/lib-src/portaudio-v19/include/pa_win_wasapi.h
@@ -319,6 +319,16 @@ int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, Pa
int/*PaWasapiDeviceRole*/ PaWasapi_GetDeviceRole( PaDeviceIndex nDevice );
+/** 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 );
+
+
/** Boost thread priority of calling thread (MMCSS). Use it for Blocking Interface only for thread
which makes calls to Pa_WriteStream/Pa_ReadStream.
diff --git a/lib-src/portaudio-v19/src/hostapi/wasapi/pa_win_wasapi.c b/lib-src/portaudio-v19/src/hostapi/wasapi/pa_win_wasapi.c
index 0026033..2e9dca8 100644
--- a/lib-src/portaudio-v19/src/hostapi/wasapi/pa_win_wasapi.c
+++ b/lib-src/portaudio-v19/src/hostapi/wasapi/pa_win_wasapi.c
@@ -375,6 +375,9 @@ typedef struct PaWasapiDeviceInfo
// Formfactor
EndpointFormFactor formFactor;
+
+ // Loopback indicator
+ int loopBack;
}
PaWasapiDeviceInfo;
@@ -1179,6 +1182,8 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
HRESULT hr = S_OK;
IMMDeviceCollection* pEndPoints = NULL;
UINT i;
+ UINT renderCount;
+ UINT devIndex;
if (!SetupAVRT())
{
@@ -1275,6 +1280,19 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
}
}
+ hr = IMMDeviceEnumerator_EnumAudioEndpoints(paWasapi->enumerator, 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(paWasapi->enumerator, eAll, DEVICE_STATE_ACTIVE, &pEndPoints);
// We need to set the result to a value otherwise we will return paNoError
// [IF_FAILED_JUMP(hResult, error);]
@@ -1285,6 +1303,8 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
// [IF_FAILED_JUMP(hResult, error);]
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
+ paWasapi->deviceCount += renderCount;
+
paWasapi->devInfo = (PaWasapiDeviceInfo *)PaUtil_AllocateMemory(sizeof(PaWasapiDeviceInfo) * paWasapi->deviceCount);
if (paWasapi->devInfo == NULL)
{
@@ -1313,7 +1333,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
goto error;
}
- for (i = 0; i < paWasapi->deviceCount; ++i)
+ for (devIndex = 0, i = 0; i < paWasapi->deviceCount; ++i, ++devIndex)
{
DWORD state = 0;
PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
@@ -1323,7 +1343,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
PA_DEBUG(("WASAPI: device idx: %02d\n", i));
PA_DEBUG(("WASAPI: ---------------\n"));
- 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);
@@ -1513,6 +1533,43 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
(*hostApi)->deviceInfos[i] = deviceInfo;
++(*hostApi)->info.deviceCount;
+
+ if (paWasapi->devInfo[i].flow == eRender)
+ {
+ char *deviceName;
+ UINT deviceNameLen;
+
+ 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;
+ }
}
}
@@ -1691,6 +1748,29 @@ const wchar_t *PaWasapi_GetOutputDeviceID( PaStream* s )
}
// ------------------------------------------------------------------------------------------
+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 *nInput, unsigned int *nOutput )
{
PaWasapiStream *stream = (PaWasapiStream *)pStream;
@@ -2336,7 +2416,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
}*/
// select mixer
- pSub->monoMixer = _GetMonoToStereoMixer(WaveToPaFormat(&pSub->wavex), (pInfo->flow == eRender ? MIX_DIR__1TO2 : MIX_DIR__2TO1_L));
+ pSub->monoMixer = _GetMonoToStereoMixer(WaveToPaFormat(&pSub->wavex), (output ? MIX_DIR__1TO2 : MIX_DIR__2TO1_L));
if (pSub->monoMixer == NULL)
{
(*pa_error) = paInvalidChannelCount;
@@ -2621,7 +2701,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
}*/
// Select mixer
- pSub->monoMixer = _GetMonoToStereoMixer(WaveToPaFormat(&pSub->wavex), (pInfo->flow == eRender ? MIX_DIR__1TO2 : MIX_DIR__2TO1_L));
+ pSub->monoMixer = _GetMonoToStereoMixer(WaveToPaFormat(&pSub->wavex), (output ? MIX_DIR__1TO2 : MIX_DIR__2TO1_L));
if (pSub->monoMixer == NULL)
{
(*pa_error) = paInvalidChannelCount;
@@ -2941,6 +3021,9 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
if (fullDuplex)
stream->in.streamFlags = 0; // polling interface is implemented for full-duplex mode also
+ 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);
|