Some audio devices, like Microsoft’s LifeChat LX-3000 USB handset, have different input and output sample rates (41.1k & 48k Hz in its case), and JUCE with Windows Audio (WASAPI) doesn’t support that.
But, since Windows 8 it seems that Windows Audio supports SRC, if you ask it to. So I made a commit to enable it. Seems to work Many thanks to PortAudio whose source I looked at to discover the right Win API chants for this.
Feel free to use it (note that our master branch is JUCE 5 based, and there’s also a juce6 branch available) and/or incorporate it into JUCE!
Thanks for the patch! We’ve added this to develop in b01e927 with a few modifications -
The Audiosessiontypes.h and audioclient.h headers aren’t required as we can do local declarations for the bits we need (as we do already). This also means we don’t need to bump the WINNT define.
When querying supported sample rates, IsFormatSupported() can succeed with a nearest supported format so we need to check the sample rate of this if it is valid otherwise all sample rates will “succeed” even though they aren’t supported by the device.
AUDCLNT_STREAMOPTIONS_MATCH_FORMAT isn’t required for SRC so we can remove the property setting.
We need to add all supported input and output device sample rates to the sampleRates array.
Whilst poking around in the WASAPI code, we’ve also added support for low latency shared streams via the IAudioClient3 interface in 6195a5a.
I tested your patch and it doesn’t seem to work here with my setup. It might be worth-while to hear whether it works on some setups and doesn’t for others.
To reproduce: Using Windows 10 here with the Microsoft LifeChat LX-3000 USB headset (which only supports 48000 Hz for earphones and 44100 for mic), running the JUCE DemoRunner and going to its preferences to choose audio devices, with my fix it previously offered both rates for either its input or output or both together, and with the new fix it works like it did before (can only pick input with its rate, output with its rate, and can’t pick them together).
I know that the Windows API chants can be mysterious and that it may be difficult to find how to actually enable something and the code may have some spurious stuff left. So I understand that you suspected that some of my changes are not required. But I did make an effort to only keep the bare-minimum actually required API chants.
No, I don’t think it’s required and the reason for removing in the commit is because I think it’s actually incorrect. When using AUDCLNT_STREAMOPTIONS_MATCH_FORMAT you are asking the audio engine to change its mix format (the underlying stream used for shared mode) to match the proposed format in the call to Initialize(), not to perform sample rate conversion between streams. This can cause IsFormatSupported() to fail with AUDCLNT_E_UNSUPPORTED_FORMAT if you are trying to open a device with a sample rate that the mix format doesn’t actually support (I’ve seen this happen with a headset that only supports 8kHz).
I think what we should be doing instead is always using the requested sample rate if SRC is available and enabled, instead of using the one suggested by nearestFormat. Can you see if the following change to tryFormat() works for your headset?
Is this a known issue? I tried it in my Parallels VM and was able to change the buffer size for all “Windows Audio” device types so I don’t know if this problem is device specific.
Anybody else seen this?
As far as I know, the sample rate of Windows Audio have always been fixed to whatever value is selected in the OS’ control panel for the particular audio device. In contrast to DirectSound where you can choose between more values (typically 44100, 48k, 88.2k, 96k etc).
The Audio buffer size however is stuck at 448 samples (10.2ms) in Windows Audio Low latency mode but selectable (in Juce control panel) in WA mode between 132 and 2018 samples. Hence I’ve never really understood why it’s called low latency…
(Windows 10 version 2004, Focusrite external and Realtec integrated audio)
I don’t know about Waveform, but as long as I can remember dealing with the Juce framework (>6 years), I’ve never been able to change the sample rate for Windows Audio from inside the framework, e.g in the Juce demo. I guess it could depend on the actual hardware though, I`ve only used the it with four or five different audio devices.
In pre-low-latency, if I try to change assign the input as well as the input I get an error that the devices don’t share a common sample rate. In post-low-latency I get the option to do so though, is this because JUCE or the Windows layer is doing some sample-rate-conversion now so this configuration is allowed?
In Exclusive mode I used to be able to change the sample rate but now I can’t.
It would be nice to get some clarification on exactly how this behaviour has changed, at least so I can pass it on to my users. At the moment it’s like I’ve removed some functionality.
What you see directly relates to the topic of this discussion, which is the important one for me.
Background: for some reasons there are many devices that have 48k output and 44.1k input and JUCE didn’t support using them before, and now with enabling WASAPI’s built-in SRC it does! IIUC this only affects the plain “Windows Audio” mode.
Before, even if you implemented SRC yourself - JUCE wouldn’t support the audio because it only supports matching input and output sample rates. Now, you can use these devices with JUCE with WASAPI. Btw ASIO and macOS with the same devices (such as USB headsets) did work.
And the two additional recent changes to JUCE:
Exclusive mode was previously enabled only if you set some defines
But I don’t understand why my users now can’t change sample rate from JUCE for any of the Windows Audio device types. What has changed to disallow that and why?
Has anyone experience being able to change the sample rate in pre-low-latency builds on Windows before? I need to verify this behaviour before I go back to my user and tell them they were mistake, this was never possible.
In my experience, at least in “Exclusive Mode” I was able to change the sample rate:
I suggest to bisect to find when the regression was introduced. It could be that one of the two changes of enabling SRC and enabling low latency audio somehow did it. If for example it’s some flags related to SRC somehow tell Windows to stop configuring sample rate in exclusive mode, then the solution could be to not enable that flag in that mode.
Are you actually able to open an exclusive device and select one of the different sample rates? I think the line responsible for this behaviour change is here:
Previously we were using the SUCCEEDED macro which will return true for anything other than S_FALSE, but the IsFormatSupported method can also return AUDCLNT_E_UNSUPPORTED_FORMAT for formats not supported in exclusive mode:
Yeah, in pre-low-latency JUCE if I select the 8K sample rate it succeeds and playback sounds suitably low-fi.
I’d love to do bisecting and really drill in to this but I’ve got so much other stuff on my plate at the moment I don’t really have the time. I mainly just wanted to report a regression or at least get a statement about the new behaviour I can pas on to my users, even if the new behaviour has to stay.