-
Notifications
You must be signed in to change notification settings - Fork 338
Add WASAPI loopback implementation #672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@dmitrykos could you review this please |
This was marked as a draft because shauneccles discovered some issues when using other devices after testing this patch, will bug hunt tonight. |
@RossBencina yes, I will do so once have a bit of free time, I am tracking this PR already since it was proposed. I also will wait for announced @WeekendWarrior1's improvements. |
Awaiting response to Dmitry's change requests. |
Implement @dmitrykos comments from PortAudio#672
@not-matt thank you for the changes. The implementation can be improved further by calculating the number of available portaudio/src/hostapi/wasapi/pa_win_wasapi.c Line 2294 in 2a68aeb
portaudio/src/hostapi/wasapi/pa_win_wasapi.c Line 2343 in 2a68aeb
If memory is allocated once by portaudio/src/hostapi/wasapi/pa_win_wasapi.c Line 2301 in 2a68aeb
It would make implementation much simpler. Here is helper function which will return the number of eRender devices in the device list: // ------------------------------------------------------------------------------------------
static UINT32 GetRenderDeviceCount(IMMDeviceCollection *pEndPoints)
{
HRESULT hr;
UINT32 deviceCount;
IMMDevice *device;
IMMEndpoint *endpoint;
EDataFlow flow;
UINT32 ret = 0;
hr = IMMDeviceCollection_GetCount(pEndPoints, &deviceCount);
IF_FAILED_JUMP(hr, error);
for (UINT32 i = 0; i < deviceCount; ++i)
{
hr = IMMDeviceCollection_Item((IMMDeviceCollection *)pEndPoints, i, &device);
IF_FAILED_JUMP(hr, error);
if (SUCCEEDED(hr = IMMDevice_QueryInterface(device, &pa_IID_IMMEndpoint, (void **)&endpoint)))
{
if (SUCCEEDED(hr = IMMEndpoint_GetDataFlow(endpoint, &flow)))
ret += (flow == eRender);
SAFE_RELEASE(endpoint);
}
SAFE_RELEASE(device);
}
return ret;
error:
return 0;
} |
Hi @dmitrykos, thank you for the feedback. I've worked with @WeekendWarrior1 in the past but I've not been able to reach him to wrap up this PR. I can make an attempt to implement your feedback, but I have no experience writing C. If you have the time, would you consider writing these changes yourself? I'm in touch with @shauneccles and can get any changes you would make added to this PR very quickly. |
@not-matt ok, I will try to implement in the way I advised and let's see how it works then. |
Nice, cheers. Do let me know if there's anything I can help you with, especially testing. |
I have been waiting for this feature to land upstream. I maintained my own version for a couple of years. |
I made necessary cleanup changes, would you please test how it works on your side. I tested Win32 and UWP modes and it works quite well, no problems noted. Loopback mode does not support Exclusive mode though that is quite natural because it is a proxy for a playback device. If your test results confirm that all runs fine I think we could finally merge it. |
Good stuff! I'm away this weekend, I'll take a look once I'm back. |
2f8000f
to
5b17bd0
Compare
I built and linked against this PR and the loopback input works nicely! I haven't tested the |
PaWasapi_IsLoopback works as intended |
@nidefawl great, thank you for testing! |
Can confirm it behaves as expected over here on Win 10/Win 11. |
… allocations inside the CreateDeviceList(), cleaned up comment, added export for PaWasapi_IsLoopback into .def.
5b17bd0
to
605fc89
Compare
@shauneccles thank you for testing. I added comments into the source code regarding |
No issues with using square brackets that I can see/think of, it makes sense to keep them different to give people another signal that it is a loopback device. |
+1, this works well for me on Windows. Haven't ran into any issues. |
Thank you for proposing the PR and tests, I think it can go into the main repo! Closes #668 |
Thanks for taking the time to do this right and get it upstreamed! |
After adding loopback devices to WASAPI it looks like PaHostApiInfo::defaultInputDevice and PaHostApiInfo::defaultOutputDevice are broken. I haven't quite figured out why the indexing is not matching.
Output:
Something must be going wrong with the indexing either here and here. |
@bear101 thank you for reporting, I will have a look shortly. |
Hello Guys, is there any exemple of the loopback feature implementation? |
@GiuseppeUFSM You don't need any special code to use this feature. Just use PortAudio normally and the "virtual" loopback devices will just naturally show up in the usual list of input devices. In fact it should even work in existing applications if you replace their PortAudio DLL. |
Re implements this patch: audacity/audacity@be7467c#diff-6ea9c8ba5ecef609fc4cfa9fbbb1bc11ad66acb997565df06ad6ce1562a10144 to add loopback for WASAPI devices.
I'm very new to C so I welcome any feedback or improvements to this PR.
Closes this:
#668
And would really help python-sounddevice users:
spatialaudio/portaudio-binaries#6
spatialaudio/python-sounddevice#287
tlecomte/friture#64
spatialaudio/python-sounddevice#281
spatialaudio/python-sounddevice#14
Also see this project which maintains a fork of portaudio with loopback support specifically for PyAudio: https://github.com/intxcc/pyaudio_portaudio