AFAIK, older FMOD Ex wasn’t thread-safe.
It’s very nice that we don’t have to think too much about thread-safe design with FMOD Studio anymore.
But I wonder if too many FMOD function calls in very a short time will disturb FMOD system threads (due to locks).
I mean, I have a worker thread that keeps calling FMOD_System_Update() in a loop.
That thread also calls many other FMOD functions.
Firstly, it traces every sound object created by the main thread by calling FMOD_Channel_IsPlaying().
If it returns false, the object will be removed after FMOD_Channel_RemoveDSP() is called.
Otherwise, FMOD_Channel_SetVolume() may be called to simulate fade-out, or FMOD_Channel_Stop() may be called if there’s a stop request from the main thread.
And the main thread calls FMOD_System_PlaySound() when there’s input from a user, MIDI file, etc.
I simplified things here, so there are actually more FMOD function calls in both threads.
Because too many sound objects can be created by the main thread and the worker thread keeps running with almost zero sleep time (for responsiveness), I think FMOD threads may be impacted.
Should I add a little longer sleep time to the worker thread?
(The worker thread’s priority is lower than FMOD’s.)
Interesting question- the default behaviour of the Core API is that, where possible, commands that cannot be executed in any given call to FMOD_System_Update()
are moved to the next call. Perhaps there is an upper limit to how many of these calls you can make before they start getting dropped or you run out of memory, but I think that situation would be an edge case.
General usability rule for system responsiveness is that 100ms is pereceived as instantaneous, so I do not think you need a close-to-zero sleep time between calls to FMOD_System_Update()
. We use 50ms in the API examples and that is a sensible minimum.
1 Like
I didn’t know that Core API works that way.
Thank you!
But still, even to check the upper limit, I think Core API needs either lock or atomic/volatile variables, and that means too many FMOD function calls from different threads may be harmful.
So my guess is that only the FMOD_System_Update() function call interrupts feeder or/and mixer threads.
Other FMOD function calls only interrupt the thread where those are called and FMOD_System_Update() is called.
Am I correct?
I’ll take the general usability rule, but I’m asking this just to better understand the FMOD system.
Yes, Core API has mutexes around the public API functions, so at the upper limit of API calls, the thread you are calling the API from will be unresponsive, but that won’t affect audio output- something blocking the mixer thread on the other hand is where you start getting problems with buffer starvation, with intermittent silence and glitching.
FMOD_System_Update()
does not interrupt the mixer thread, it just commits changes to parameters, 3d positions and things like that.
1 Like
Oh, one last question!
I’m calling FMOD_System_Init() with the FMOD_INIT_STREAM_FROM_UPDATE flag not to create the stream thread.
That means updating the stream engine can be done only by FMOD_System_Update().
So I wonder if calling the function every 100ms (as you said) would be enough for streaming any file type too.
Interesting point, as a test I ran one of our API example with the setup you’ve described- the 100ms sleep works fine, but setting from about 200ms onwards results in the mixer thread looping the existing buffer repeatedly until the next call to FMOD_System_Update()
, which repopulates the buffer and starts looping that, so on and so fourth until the stream finishes. So this would mean that slow and blocking operations would create glitches in the audio as it continues recylcing the old buffer.
Perhaps if you wanted to run it in the FMOD_INIT_STREAM_FROM_UPDATE mode you should set it to a lower value.
1 Like