1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-09 23:34:20 +00:00

AudioDeviceManager: Move CallbackMaxSizeEnforcer from StandaloneFilterWindow

This commit is contained in:
reuk 2025-05-21 19:43:19 +01:00
parent 28a2700a28
commit ee37564083
No known key found for this signature in database
2 changed files with 100 additions and 97 deletions

View file

@ -459,93 +459,6 @@ private:
processor = nullptr;
}
//==============================================================================
/* This class can be used to ensure that audio callbacks use buffers with a
predictable maximum size.
On some platforms (such as iOS 10), the expected buffer size reported in
audioDeviceAboutToStart may be smaller than the blocks passed to
audioDeviceIOCallbackWithContext. This can lead to out-of-bounds reads if the render
callback depends on additional buffers which were initialised using the
smaller size.
As a workaround, this class will ensure that the render callback will
only ever be called with a block with a length less than or equal to the
expected block size.
*/
class CallbackMaxSizeEnforcer : public AudioIODeviceCallback
{
public:
explicit CallbackMaxSizeEnforcer (AudioIODeviceCallback& callbackIn)
: inner (callbackIn) {}
void audioDeviceAboutToStart (AudioIODevice* device) override
{
maximumSize = device->getCurrentBufferSizeSamples();
storedInputChannels .resize ((size_t) device->getActiveInputChannels() .countNumberOfSetBits());
storedOutputChannels.resize ((size_t) device->getActiveOutputChannels().countNumberOfSetBits());
inner.audioDeviceAboutToStart (device);
}
void audioDeviceIOCallbackWithContext (const float* const* inputChannelData,
[[maybe_unused]] int numInputChannels,
float* const* outputChannelData,
[[maybe_unused]] int numOutputChannels,
int numSamples,
const AudioIODeviceCallbackContext& context) override
{
jassert ((int) storedInputChannels.size() == numInputChannels);
jassert ((int) storedOutputChannels.size() == numOutputChannels);
int position = 0;
while (position < numSamples)
{
const auto blockLength = jmin (maximumSize, numSamples - position);
initChannelPointers (inputChannelData, storedInputChannels, position);
initChannelPointers (outputChannelData, storedOutputChannels, position);
inner.audioDeviceIOCallbackWithContext (storedInputChannels.data(),
(int) storedInputChannels.size(),
storedOutputChannels.data(),
(int) storedOutputChannels.size(),
blockLength,
context);
position += blockLength;
}
}
void audioDeviceStopped() override
{
inner.audioDeviceStopped();
}
private:
struct GetChannelWithOffset
{
int offset;
template <typename Ptr>
auto operator() (Ptr ptr) const noexcept -> Ptr { return ptr + offset; }
};
template <typename Ptr, typename Vector>
void initChannelPointers (Ptr&& source, Vector&& target, int offset)
{
std::transform (source, source + target.size(), target.begin(), GetChannelWithOffset { offset });
}
AudioIODeviceCallback& inner;
int maximumSize = 0;
std::vector<const float*> storedInputChannels;
std::vector<float*> storedOutputChannels;
};
CallbackMaxSizeEnforcer maxSizeEnforcer { *this };
//==============================================================================
class SettingsComponent : public Component
{
@ -682,7 +595,7 @@ private:
const String& preferredDefaultDeviceName,
const AudioDeviceManager::AudioDeviceSetup* preferredSetupOptions)
{
deviceManager.addAudioCallback (&maxSizeEnforcer);
deviceManager.addAudioCallback (this);
deviceManager.addMidiInputDeviceCallback ({}, &player);
reloadAudioDeviceState (enableAudioInput, preferredDefaultDeviceName, preferredSetupOptions);
@ -693,7 +606,7 @@ private:
saveAudioDeviceState();
deviceManager.removeMidiInputDeviceCallback ({}, &player);
deviceManager.removeAudioCallback (&maxSizeEnforcer);
deviceManager.removeAudioCallback (this);
}
void timerCallback() override