PSA for anyone using SetProgrammerSoundName with Unreal. There’s an erratic crashing bug we discovered in UFMODAudioComponent::EventCallbackCreateProgrammerSound() you should know about. It’s easy to fix in your copy of the plugin until Firelight can rev their code.
The problem is that the callback is made on the FMod thread, not on the Unreal thread. This code:
FMOD::Studio::System* System = IFMODStudioModule::Get().GetStudioSystem(EFMODSystemContext::Runtime); FMOD::System* LowLevelSystem = nullptr; System->getLowLevelSystem(&LowLevelSystem);
Is the problem, because Unreal’s module system isn’t thread safe. This means that occasionally the refcount on the IFMODStudioModule will get corrupted and the module will be freed. This, of course, is a “bad thing” because the next person to access it will crash.
The bug happens when the main thread accesses module at the same time as the fmod thread is creating a programmer sound. If a thread context switch happens at just the right time (after the refcount has been read, but before it’s been incremented and set), both threads will read 1 and write 2, instead of the second thread reading 2 and writing 3. Then when they deref the count goes to 0 and boom. We were hitting this erratically every day testing our game.
The fix is is to cache the system pointer (which shouldn’t change anyway) at startup:
In FMODAudioComponent.h, at the end of the class definition:
// AFTER THIS:
// Direct assignment of programmer sound from other C++ code
// ADD THIS:
In FMODAudioComponent.cpp, at the end of the constructor, add this:
// Set the system here, on the main thread, because we can't get it during callbacks on the fmod thread to create programmer sounds System = IFMODStudioModule::Get().GetStudioSystem(EFMODSystemContext::Runtime);
And in EventCallbackCreateProgrammerSound() you can comment out this line:
//FMOD::Studio::System* System = IFMODStudioModule::Get().GetStudioSystem(EFMODSystemContext::Runtime);
FMOD::System* LowLevelSystem = nullptr;
since System is now a member variable on the component. This resolves the multithread issue because the constructor runs on the Unreal thread.
I hope this helps someone else with mysterious crashes