ValveSoftware / steam-audio

Steam Audio
https://valvesoftware.github.io/steam-audio/
Apache License 2.0
2.2k stars 152 forks source link

[Unity/Fmod] Enable and disabling between listener components breaks the spatializer #323

Closed Warmacha closed 3 months ago

Warmacha commented 3 months ago

System Information Please provide the following information about your system:

Issue Description When turning off the fmod studio listener and steam audio listener on one camera and enabling new ones on another, the spatializer will fail to play from the correct listener upon the Third time switching between listener components. It will work fine when switching the first time, but every time after it will listen from the incorrect position. If the problematic gameobject is deleted, then the spatializer only listens to sounds from origin instead of from any active listeners.

Steps To Reproduce Steps to reproduce the behavior:

  1. Setup a basic scene with basic geometry bakes and pathing
  2. Use any steam audio spatializer sound on Fmod with simulation defined enabled on everything that allows it except for attenuation. apply hrtf on reflection and pathing.
  3. Set up 2 camera's in the scene with the Fmod studio listener and Steam audio listener, have one with it's components enabled and another with it's components disabled.
  4. place a third gameobject with the fmod event emitter and steam audio source components.
  5. Press play and cycle between game object listeners by turning off the components and playing the sound event, this can be done manually with no extra scripts.
  6. Bug should be observable after the 2nd time cycling through.

One thing to note, Fmods normal spatializer works just fine under these circumstances, only the Steam Audio Spatializer seems to fail.

https://github.com/ValveSoftware/steam-audio/assets/44778343/3ee108e3-da1f-4d9c-b12e-27b9cbbb5c05

Warmacha commented 3 months ago

The issue is due to the Steam Audio Manager not updating it's listeners when they are changed. There is a dedicated method within it called NotifyAudioListenerChanged() which is supposed to handle updating the listeners transform, however it is only called when a new scene is loaded and requires manual calling from somewhere outside in order to Update.

Biggest problem with it though is that the method relies on a FindObjectOfType call, meaning the listener that is returned isn't guaranteed to be the correct one if more than one is present regardless of its enabled state.

An easy way to get around this is by manually passing the current listeners transform from outside, we have our own Audio Manager that keeps track of our listeners which we use to pass in the correct one to Steams Audio Manager.

Just put this in SteamAudioManager and pass in you're current listeners transform.

        /// Manually pass in the correct Listeners transform from our own Audio Manager.
        /// </summary>
        /// <param name="_listener"></param>
        public static void PassNewAudioListener(Transform _listener)
        {
            sSingleton.mListener = _listener;
            if (sSingleton.mListener)
            {
                sSingleton.mListenerComponent = sSingleton.mListener.GetComponent<SteamAudioListener>();
            }
        }

A more general solution for the entire plugin maybe adding functionality to Steam Audio Manager to better keep track of existing listeners and update on it's own when ones turn on and off or are destroyed.