Audio stops working after changing samplerate externally

Hello JUCE,

When changing the sample rate from an external source such as Audio Midi Setup, the audio functionality in JUCE (DemoRunner) stops working. This issue is fixed by forcing JUCE to re-initialize the audio device, for instance by adjusting settings like sample rate, buffer size, or channels within the DemoRunner settings.

This problem occurs when using a matching pair device where both input and output use the same internal sample rate. There is no problem when using the mac default microphone and speaker, JUCE audio will keep working when the samplerate of one of these two changes externally.

To reproduce the problem:

  1. Launch JUCE DemoRunner.
  2. Choose a matching pair audio device for both input and output (e.g., Scarlett Solo 4th gen) within the DemoRunner audio settings.
  3. Verify AudioSynthesiserDemo.h works.
  4. Change the sample rate in Audio Midi Setup.
  5. Note that the sample rate in DemoRunner Settings remains unchanged.
  6. Note that AudioSynthesiserDemo.h no longer makes any sound.

Test setup:

  • JUCE DemoRunner 7.0.11
  • macOS 14.3.1 (23D60)
  • M1 chip
  • Tested with Scarlett Solo 4th gen and Audient ID22

Best,

Jelle

Hi Jelle,
I usually work around this using a Timer.
It basically boils down to:

  • Have a Timer running with a non expensive speed, e.g. 1 second
  • In the timerCallback implementation, check that the app is the currently focused one (juce::TopLevelWindow::getActiveTopLevelWindow() comes to the rescue)
  • If the app is the currently focused one, check the value of your desired sample rate against the one that’s currently being set by the device
  • If they don’t match (and the device supports the desired sample rate, this is important as it can happen also on Windows where WASAPI is a bit obtuse), reconfigure the AudioDeviceManager accordingly

Please note that in my case I want to “force” the sample rate that I want in my app.
If you instead would like to “adapt” to the current sample rate set by CoreAudio then you could maybe use the same workaround but with some adjustments at the end.

Hope this helps :wink:

@masshacker your timer approach looks useful when a specific sample rate is required. However, in my application, the specific sample rate isn’t a requirement, I simply want JUCE audio functionality to remain working. I presumed that this would be handled automatically by JUCE.

I assumed the issue I reported was a bug but after the comment by @masshacker I realized I might be wrong. Could someone from the JUCE team reply?

The AudioDeviceManager is a ChangeBroadcaster. Have you tried to add a listener and call restartLastAudioDevice() there?

I could… but how do I know if the device is not running? Also, isn’t it the responsibility of device manager to take care of it automatically?

If the sampleRate changes, the audio pipeline i.e. your code has to be prepared fresh by calling AudioIODeviceCallback::audioDeviceAboutToStart() so you can prepare your buffers etc. according to the new settings.

Some code might want to do other things as well and not blindly restarting.

Hence it is an opt-in feature.

If this is the reasoning then there is some inconsistencies in behaviour:

If I select in DemoRunner “MacBook Air Microphone” as input and “MacBook Air Speakers” as output and change the samplerate of either of these in Audio Midi Setup, then the DemoRunner will automatically change the samplerate to follow that new samplerate.

However, if I set input or output to << none >> OR use a matching input/output device like in my initial description then the DemoRunner doesn’t automatically change the samplerate.

I am second guessing the API, I haven’t written it.
Maybe you get an answer from the authors

1 Like

Had the JUCE team anything to say about this?

Thanks for your patience on this issue, things have been quite hectic here lately!

We pushed a change to the develop branch at the end of last week which should resolve an issue where audio devices were not restarted correctly after their samplerate was changed externally.

I’m not completely sure that this is the same issue you’re seeing (it’s not limited to matching-pair devices), but the symptoms sound similar, i.e. the displayed samplerate is not updated and audio output ceases. Given this, there’s a reasonable chance that the following fix will resolve the issue you’re seeing.

Please try out the change and let us know how you get on. Thanks!

Thanks @reuk, it seems to have fixed our issue.

1 Like

For the sake of completeness, this fix is also available on the JUCE8 branch:

Nice! Thank you @reuk.