[C-API] iplBinauralEffectApply appears to not be thread safe when used with unique instance of IPLBinauralEffect on each thread
System Information
- Steam Audio version: 4.6.0 / 4.5.3
- Operating System and version: Windows 11
- CPU architecture: x64-64
Issue Description I am integrating Steam Audio with my custom engine using the C API (using a C# wrapper: https://github.com/Mirsario/SteamAudio.NET)
My audio engine is heavily multi-threaded. I call the iplBinauralEffectApply to spatialize multiple audio sources from multiple thread workers.
Each thread processes one audio source. Each audio source has its own instance of IPLBinauralEffect and own instances of buffers - meaning those aren't shared across threads.
When I render audio this way, the resulting audio has random blips and corruptions, often just in a single channel. If I make this processing single threaded, then everything is fine.
I tried replacing the 4.5.3 version of the library from the C# wrapper with 4.6.0 and the issue still occurs.
I am unsure if this is a bug or if I am using the API incorrectly - the documentation doesn't seem to indicate that the method would not be thread safe, but perhaps I'm missing something?
I have also confirmed that the issue isn't coming from other parts of my audio engine - if I replace the iplBinauralEffectApply call with just a copy of the input buffers to output, everything is fine (except not spatialized of course).
Steps To Reproduce Steps to reproduce the behavior:
- Create IPL context &
IPLHRTF(happens on single thread) - Create
IPLBinauralEffect& buffers for multiple audio sources (also on single thread) - Run
iplBinauralEffectApplyfrom multiple threads, each thread processing each individual audio source using its own instance ofIPLBinauralEffect
I can provide sample project if needed, but I first wanted to check if I'm doing something wrong with the API.
I've rendered both the single-threaded and multi-threaded behavior into .wav files here (WARNING: The glitches in multithreaded one are loud): AudioFiles.zip
I have found additional information. If I run iplHRTFCreate to create a unique instance of IPLHRTF for each instance of IPLBinauralEffect, then the issue also disappears.
It seems that it occurs when all instances of IPLBinauralEffect share the same instance of IPLHRTF, then they are not thread-safe, but if each one has its own copy, then they can be executed fine.
However this feels "wrong" to me, given that iplHRTFCreate function is heavy to instantiate and it's bound to each IPLBinauralEffect at instantiation of the binaural effect - meaning I couldn't just have a small pool of IPLHRTF instances and then use those dynamically when rendering each binaural effect.
Is this the intended way to use them?
@Frooxius You are correct, in that IPLHRTF is currently safe to use only from a single thread. If you need to use an HRTF from multiple threads, you'll have to create an IPLHRTF on each thread. Since IPLHRTF is a rather heavyweight object, this may be less than ideal. Some thoughts on how to make this better:
- If you use a thread pool with a fixed number of threads, and run each
IPLBinauralEffecton one of those threads, then you only need a singleIPLHRTFper thread, rather than per source. You can re-use anIPLHRTFwith multipleIPLBinauralEffectobjects, as long as they all run on the same thread. - There is probably room to refactor
IPLHRTFso that the non-thread-safe portion is its own object that can be created per-thread, while the bulk of the object (which is just the HRTF data with various pre-calculations applied) can be shared safely across threads. However, this will be a more involved task.