In a 5.8 packaged build, a Niagara System with Spectrum Audio Data causes a freeze 100% reliably. From my investigation into this, it seems to be caused by sending a command to the audio thread from the game thread, and then immediately waiting on a task in the game thread that relies on that audio thread command finishing, but the audio thread never processes its commands.
The Niagara Component’s initialization UNiagaraDataInterfaceAudioSpectrum::InitPerInstanceData, which calls FNDIAudio_GeneratedData::GetSharedResource, which initializes an FNDIAudio_SharedResource and adds it as a SubmixListener to I believe the main Submix. FNDIAudio_SharedResourceImpl::AddSubmixListener, which eventually calls FMixerDevice::RegisterSubmixBufferListener, which creates a lambda and passes it to FAudioThread::RunCommandOnAudioThread. In editor, there is no audio thread so it just runs this command immediately on the game thread. In a packaged build however, this gets enqueued onto the audio thread’s task list to be run later. Immediately afterwards, FNDIAudio_SharedResourceImpl::CollectAudio runs, and this is where the infinite Wait() happens.
The Audio Device Thread, which continuously runs, is procesing all of its buffers, including the Submix Buffer that we want our Spectrum Audio resource to listen to. It calls FOutputBuffer::MixNextBuffer -> FMixerDevice::OnProcessAudioStream -> FMixerSubmix::ProcessAudio, which would notify our Spectrum Audio listeners and mark them as complete, which would allow the task the main thread is waiting on to close. However, the command that was sent to the audio thread to register our Spectrum Audio resource as listeners never runs. As far as I can tell, the audio thread gets its commands flushed in GameEngine.cpp on the game thread, from FAudioDeviceManager::UpdateActiveAudioDevices, eventually calling an update function that calls FAudioThread::ProcessAllCommands. This sequence of functions never happens though, because the game thread starts waiting on the task almost immediately after the audio thread command is queued up. So the Audio Device thread is processing our audio, but our Spectrum Audio resources aren’t registered as listeners, their task is never marked as finished, and we wait indefinitely.
I’ve been able to temporarily fix this issue by inserting a call to FAudioThread::ProcessAllCommands in NiagaraGeneratedDataAudioSampling.cpp on line 973, right before CollectAudio() is called. This forces the submix buffer listener registration to happen so that the waited on task can complete. There’s probably a better way to fix this though.