Hi,
When using AudioDeviceManager with input-only configuration and a non-default buffer size, the audio callback does not receive the expected number of samples per second, despite the device reporting a sample rate of 44100 Hz.
Details
Expected Behavior:
At 44100 Hz sample rate, the audio callback should receive 44100 samples per second.
Actual Behavior:
The actual number of samples received per second is significantly less than the reported sample rate, proportional to the selected buffer size
Preconditions
- No output channels enabled
- Windows Audio device type
- Buffer size is smaller than the device’s default buffer size
Environment:
- OS: Windows
- Latest JUCE
Minimal Reproducible Example
#include <juce_audio_devices/juce_audio_devices.h>
class AudioExample : private juce::AudioIODeviceCallback, private juce::Timer
{
public:
AudioExample ()
{
deviceManager.initialiseWithDefaultDevices (1, 0);
deviceManager.addAudioCallback (this);
// after 10 seconds, change the buffer size to a lower buffersize
juce::Timer::callAfterDelay (10000, [&]
{
auto setup = deviceManager.getAudioDeviceSetup();
setup.bufferSize = 224;
setup.inputChannels = 1;
setup.outputChannels = 0;
if (const auto err = deviceManager.setAudioDeviceSetup(setup, true); err.isNotEmpty())
{
DBG (err);
jassertfalse;
}
});
startTimerHz (1);
}
~AudioExample() override
{
deviceManager.removeAudioCallback (this);
}
private:
juce::AudioDeviceManager deviceManager;
void audioDeviceIOCallbackWithContext (const float* const* inputChannelData,
int numInputChannels,
float* const* outputChannelData,
int numOutputChannels,
int numSamples,
const juce::AudioIODeviceCallbackContext&) override
{
juce::ignoreUnused (inputChannelData, numInputChannels, outputChannelData, numOutputChannels);
sampleCount += numSamples;
}
void audioDeviceAboutToStart (juce::AudioIODevice* audioDevice) override
{
DBG("Started device " + audioDevice->getName() + " (" + audioDevice->getTypeName() + ") with sampleRate and buffer size: "
<< audioDevice->getCurrentSampleRate() << ", " << audioDevice->getCurrentBufferSizeSamples());
}
void audioDeviceStopped() override
{
DBG ("Stopped");
}
void audioDeviceError (const juce::String& errorMessage) override
{
DBG (errorMessage);
jassertfalse;
}
std::atomic<int> sampleCount { 0 };
void timerCallback() override
{
// when the buffesize is changed to 224, we should see around 44100 samples processed per second
// but on average we receive around 22400 samples per second
DBG("Samples processed in one second: " << sampleCount.exchange(0));
}
};
int main()
{
const juce::ScopedJuceInitialiser_GUI _guiInitializer;
const auto mm = juce::MessageManager::getInstance();
AudioExample example;
mm->runDispatchLoop();
return 0;
}
See logs:
Started device Analog (1+2) (RME Fireface UCX II) (Windows Audio) with sampleRate and buffer size: 44100, 441
Samples processed in one second: 44100
Samples processed in one second: 44100
Samples processed in one second: 44100
Samples processed in one second: 44100
Samples processed in one second: 44541
Samples processed in one second: 44100
Samples processed in one second: 44100
Samples processed in one second: 44100
Samples processed in one second: 44100
Stopped
The thread 'JUCE v8.0.10: WASAPI' (37296) has exited with code 0 (0x0).
'AudioBugExample.exe' (Win32): Loaded 'C:\Windows\System32\avrt.dll'. Symbol loading disabled by Include/Exclude setting.
'AudioBugExample.exe' (Win32): Unloaded 'C:\Windows\System32\avrt.dll'
Started device Analog (1+2) (RME Fireface UCX II) (Windows Audio) with sampleRate and buffer size: 44100, 224
Samples processed in one second: 43659
Samples processed in one second: 22400
Samples processed in one second: 22624
Samples processed in one second: 22400
CMake used:
cmake_minimum_required(VERSION 3.15)
set(CMAKE_CXX_STANDARD 23)
project(AudioBugExample VERSION 0.0.1)
file(
DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/CPM.cmake
${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake
)
include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake)
CPMAddPackage(
NAME JUCE
GITHUB_REPOSITORY juce-framework/JUCE
GIT_TAG master
)
juce_add_console_app(AudioBugExample)
target_sources(AudioBugExample PRIVATE AudioBugExample.cpp)
target_link_libraries(AudioBugExample
PRIVATE
juce::juce_audio_utils
PUBLIC
juce::juce_recommended_config_flags
juce::juce_recommended_lto_flags
juce::juce_recommended_warning_flags
)
