Audio initialization difference between template audio app and AudioPluginHost

When I initialize the audio of JUCE audio application at startup using the default code from JUCE app template, AudioAppComponent::prepareToPlay() gets called correctly.

But if I use the initialization code from AudioPluginHost, AudioAppComponent::prepareToPlay() doesn’t get called at all. What’s going on? What’s the difference between those two ways of initializing the audio?

The JUCE app template seems to call setAudioChannels(), but AudioPluginHost never makes any call to that method at all. Below are the two pieces of code for reference.

JUCE audio application template audio initialization:

    if (juce::RuntimePermissions::isRequired(juce::RuntimePermissions::recordAudio)
        && !juce::RuntimePermissions::isGranted(juce::RuntimePermissions::recordAudio))
    {
        RuntimePermissions::request(RuntimePermissions::recordAudio,
            [&](bool granted) { setAudioChannels(granted ? 256 : 0, 256); });
    } else  {
        setAudioChannels(256, 256);
    }

AudioPluginHost audio initialization:

    RuntimePermissions::request(RuntimePermissions::recordAudio,
                                [&] (bool granted) mutable
                                {
                                    deviceManager.initialise(granted ? 256 : 0, 256, nullptr, true);
                                });

Anyone have any insight to this?

JUCE documentation says: “An AudioSource has two states: prepared and unprepared.”

But there is nowhere any mentioned how to even check in which state the AudioSource is. This might share some light into figuring out what is going on with my issue, AudioAppComponent is inherited from AudioSource.

The AudioPluginHost uses an AudioProcessorPlayer to interface with the AudioDeviceManager. The first initialise call doesn’t yet start processing the audio. The audio is actually started in GraphEditorPanel.cpp with deviceManager.addAudioCallback (&graphPlayer); That calls prepareToPlay on the assigned AudioProcessor and starts playing the audio with calls to processBlock.

The AudioAppComponent uses an AudioSourcePlayer and prepareToPlay is called and the audio processing starts when you call the setAudioChannels method.

1 Like

Ah, OK, makes sense now. Then they’re actually very similar with only tiny differences. Now it works. Here’s what I ended up doing based on your information:

Setting up:

    RuntimePermissions::request(RuntimePermissions::recordAudio,
                                [&] (bool granted) mutable
                                {
                                    juce::String error = deviceManager.initialise(granted ? 256 : 0, 256, nullptr, true);
                                    jassert(error.isEmpty());
                                });

    deviceManager.addAudioCallback(&audioSourcePlayer);
    audioSourcePlayer.setSource(this);

Shutting down:

    audioSourcePlayer.setSource(nullptr);
    deviceManager.removeAudioCallback(&audioSourcePlayer);

    // other audio callbacks may still be using the device
    deviceManager.closeAudioDevice();

And “this” is inherited from juce::AudioSource.

And “this” class owns the following which aren’t touched outside the above pieces of code, when initializing/deinitializing the audio:

    AudioDeviceManager      deviceManager;
    AudioSourcePlayer       audioSourcePlayer;

Just to be sure: When changing the audio device / sample rate / audio buffer size while the application is running, should the audio device first be closed or the audio callbacks be removed, or something similar? I’m developing Windows/macOS/Linux software.

I did some testing and noticed that AudioPluginHost crashes and/or doesn’t send audio fairly often, after audio config sample rate has been changed from 44100 to 88200. I have MOTU Track16 which should be easily able to handle the audio buffer size of 512 which is there by default, so that can’t be the cause of the bug.

When the AudioPlugiHost crashes, it happens in the method:

void audioCallback (const AudioTimeStamp* inputTimestamp,
                        const AudioTimeStamp* outputTimestamp,
                        const AudioBufferList* inInputData,
                        AudioBufferList* outOutputData)

In line 783:

*dest++ = *src;

The “src” is “4”, which obviously can’t be right.

And this is what the JUCE debug output reports:

2024-05-10 11:33:40.110292+0300 AudioPluginHost[13966:477243] [AudioHAL_Client] HALC_ProxySystem.cpp:143:GetObjectInfo:  HALC_ProxySystem::GetObjectInfo: got an error from the server, Error: 560947818 (!obj)
2024-05-10 11:33:40.111018+0300 AudioPluginHost[13966:477243] [AudioHAL_Client] HALC_ShellDevice.cpp:3431:RebuildSubDeviceList:  HALC_ShellDevice::RebuildSubDeviceList: couldn't find the subdevice object
2024-05-10 11:33:40.111276+0300 AudioPluginHost[13966:477243] [AudioHAL_Client] HALC_ProxySystem.cpp:143:GetObjectInfo:  HALC_ProxySystem::GetObjectInfo: got an error from the server, Error: 560947818 (!obj)
2024-05-10 11:33:40.111907+0300 AudioPluginHost[13966:477243] [AudioHAL_Client] HALC_ShellDevice.cpp:3431:RebuildSubDeviceList:  HALC_ShellDevice::RebuildSubDeviceList: couldn't find the subdevice object

Please can you provide the following information:

  • Do you see the crash when only ‘internal’ nodes are present in the processor graph?
  • On what OSes and OS versions do you see the crash? From the log it looks like some version of macOS, is that correct?
  • How are you changing the samplerate? Are you using the settings pane in the AudioPluginHost itself, or are you changing the samplerate externally, e.g. through Audio Midi Settings?

I switch the sample rate from AudioPluginHost’s own settings.

When I use only ‘internal’ nodes (no plugins anywhere), the crash disappears and the stability of switching between audio interface sample rates seems to produce less buggy results.

However, only the 44100 Hz sample rate seems to produce any output on Mac (Windows 10 seems to work fine). I tested this by routing audio interfaces audio inputs directly to its own outputs in AudioPluginHost. Every time I used 44100 Hz sample rate the sound passed without issues through my audio interface. If I changed the sample rate to anything else, I heard nothing from the speakers.

The crash, when a plugin is used in AudioPluginHost, happens on macOS Mojave.

Thanks for the additional info.

Is it possible that the crash is caused by an external plugin, in that case? If you inspect the stack trace at the point of the crash, is it in a specific plugin each time?

That’s more strange. Are the audio inputs and outputs both on the MOTU device, or are you using separate devices? It sounds like you’re using the MOTU for both input and output, is that correct?

Can you confirm that you see the same behaviour when building the AudioPluginHost from latest develop?

We pushed a fix for another issue with audio devices on macOS very recently. I don’t know whether it’s exactly the same issue, but perhaps it’s related:

Correct. I’m using the same MOTU for both in and out devices.

I just updated the JUCE to latest develop version. The bug still exists but is apparently behaving a bit differently now. I’m not sure if it’s due to the new version of JUCE or something else. Here’s the description of what I observed:

I set up AudioPluginHost running no plugins at all. Just the audio passing through MOTU’s inputs to its own outputs, routed using AudioPluginHost.

AudioPluginHost’s sample rate had been set to 88200 Hz the last time I used it, so it was set to that value when I ran AudioPluginHost again. Immediately when running the software I could hear the audio passing through the audio interface correctly.

Then when I changed to 44100 Hz, it worked again correctly.

I switched couple of times between various sample rates (44100 Hz, 88200 Hz or 96000 Hz and then back again to smaller ones). At some point when I changed the sample rate, the audio stopped. Then when I switched the sample rate maybe one or two times more, AudioPluginHost crashed.

The crash happened in the file juce_CoreAudio_mac.cpp, on line 783, in the method void audioCallback(…)
The exact line is:

*dest++ = *src;

“dest” looks like it’s a valid pointer. “src” is set to “4”, which again looks like an invalid pointer to me.

The debugger shows the “info” variable set to:

info	const juce::CoreAudioClasses::CoreAudioInternal::CallbackDetailsForChannel &	0x0000600003717b04

Here’s all the debug output JUCE printed out while the application was running and I was switching between the various sample rates:

2024-05-14 14:56:18.584771+0300 AudioPluginHost[5094:110927] [DYMTLInitPlatform] platform initialization successful
JUCE v7.0.12
2024-05-14 14:56:20.373532+0300 AudioPluginHost[5094:110684] Metal GPU Frame Capture Enabled
2024-05-14 14:56:20.375113+0300 AudioPluginHost[5094:110684] Metal API Validation Enabled
2024-05-14 14:56:29.058722+0300 AudioPluginHost[5094:110937] [AudioHAL_Client] HALC_ProxySystem.cpp:143:GetObjectInfo:  HALC_ProxySystem::GetObjectInfo: got an error from the server, Error: 560947818 (!obj)
2024-05-14 14:56:29.059317+0300 AudioPluginHost[5094:110937] [AudioHAL_Client] HALC_ShellDevice.cpp:3431:RebuildSubDeviceList:  HALC_ShellDevice::RebuildSubDeviceList: couldn't find the subdevice object
2024-05-14 14:56:37.623728+0300 AudioPluginHost[5094:110929] [AudioHAL_Client] HALC_ProxySystem.cpp:143:GetObjectInfo:  HALC_ProxySystem::GetObjectInfo: got an error from the server, Error: 560947818 (!obj)
2024-05-14 14:56:37.624704+0300 AudioPluginHost[5094:110929] [AudioHAL_Client] HALC_ShellDevice.cpp:3431:RebuildSubDeviceList:  HALC_ShellDevice::RebuildSubDeviceList: couldn't find the subdevice object
2024-05-14 14:56:54.861244+0300 AudioPluginHost[5094:111511] [AudioHAL_Client] HALC_ProxySystem.cpp:143:GetObjectInfo:  HALC_ProxySystem::GetObjectInfo: got an error from the server, Error: 560947818 (!obj)
2024-05-14 14:56:54.862040+0300 AudioPluginHost[5094:111511] [AudioHAL_Client] HALC_ShellDevice.cpp:3431:RebuildSubDeviceList:  HALC_ShellDevice::RebuildSubDeviceList: couldn't find the subdevice object
2024-05-14 14:57:00.790226+0300 AudioPluginHost[5094:111676] [AudioHAL_Client] HALC_ProxySystem.cpp:143:GetObjectInfo:  HALC_ProxySystem::GetObjectInfo: got an error from the server, Error: 560947818 (!obj)
2024-05-14 14:57:00.790979+0300 AudioPluginHost[5094:111676] [AudioHAL_Client] HALC_ShellDevice.cpp:3431:RebuildSubDeviceList:  HALC_ShellDevice::RebuildSubDeviceList: couldn't find the subdevice object
2024-05-14 14:57:00.791402+0300 AudioPluginHost[5094:111676] [AudioHAL_Client] HALC_ProxySystem.cpp:143:GetObjectInfo:  HALC_ProxySystem::GetObjectInfo: got an error from the server, Error: 560947818 (!obj)
2024-05-14 14:57:00.792670+0300 AudioPluginHost[5094:111676] [AudioHAL_Client] HALC_ShellDevice.cpp:3431:RebuildSubDeviceList:  HALC_ShellDevice::RebuildSubDeviceList: couldn't find the subdevice object
2024-05-14 14:57:10.475304+0300 AudioPluginHost[5094:111833] [AudioHAL_Client] HALC_ProxySystem.cpp:143:GetObjectInfo:  HALC_ProxySystem::GetObjectInfo: got an error from the server, Error: 560947818 (!obj)
2024-05-14 14:57:10.476378+0300 AudioPluginHost[5094:111833] [AudioHAL_Client] HALC_ShellDevice.cpp:3431:RebuildSubDeviceList:  HALC_ShellDevice::RebuildSubDeviceList: couldn't find the subdevice object
2024-05-14 14:57:10.476711+0300 AudioPluginHost[5094:111833] [AudioHAL_Client] HALC_ProxySystem.cpp:143:GetObjectInfo:  HALC_ProxySystem::GetObjectInfo: got an error from the server, Error: 560947818 (!obj)
2024-05-14 14:57:10.477488+0300 AudioPluginHost[5094:111833] [AudioHAL_Client] HALC_ShellDevice.cpp:3431:RebuildSubDeviceList:  HALC_ShellDevice::RebuildSubDeviceList: couldn't find the subdevice object
2024-05-14 14:57:18.225221+0300 AudioPluginHost[5094:110684] [AudioHAL_Client] HALB_IOThread.cpp:251:_Start:  HALB_IOThread::_Start: there already is a thread
2024-05-14 14:57:30.365010+0300 AudioPluginHost[5094:112002] [AudioHAL_Client] HALC_ProxySystem.cpp:143:GetObjectInfo:  HALC_ProxySystem::GetObjectInfo: got an error from the server, Error: 560947818 (!obj)
2024-05-14 14:57:30.365782+0300 AudioPluginHost[5094:112002] [AudioHAL_Client] HALC_ShellDevice.cpp:3431:RebuildSubDeviceList:  HALC_ShellDevice::RebuildSubDeviceList: couldn't find the subdevice object
2024-05-14 14:57:30.366153+0300 AudioPluginHost[5094:112002] [AudioHAL_Client] HALC_ProxySystem.cpp:143:GetObjectInfo:  HALC_ProxySystem::GetObjectInfo: got an error from the server, Error: 560947818 (!obj)
2024-05-14 14:57:30.366751+0300 AudioPluginHost[5094:112002] [AudioHAL_Client] HALC_ShellDevice.cpp:3431:RebuildSubDeviceList:  HALC_ShellDevice::RebuildSubDeviceList: couldn't find the subdevice object
(lldb)