Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Resolved AudioSource.PlayOneShot does not persist across scenes despite DontDestroyOnLoad

Discussion in 'Audio & Video' started by Daerst, Feb 12, 2021.

  1. Daerst

    Daerst

    Joined:
    Jun 16, 2016
    Posts:
    275
    In my main menu scene, I have both the AudioListener and an AudioSource on the same GameObject, set to DontDestroyOnLoad. When I start the game from the menu, I play a sound using
    myGlobalAudioSource.PlayOneShot
    , fade the menu out and then load the first gameplay scene. For some reason, this interrupts the sound that is still being played, although neither AudioSource nor AudioListener are unloaded. Any way to fix this easily, or do I need to hook up my own DontDestroyOnLoad audio source pool for these sounds?
     
  2. bakioztepe

    bakioztepe

    Joined:
    Sep 23, 2019
    Posts:
    9
    I use the same technique but I never came across such an issue. You may need to provide a sample scene.
     
  3. Daerst

    Daerst

    Joined:
    Jun 16, 2016
    Posts:
    275
    Thanks @bakioztepe, that's good to hear - maybe I'm just doing something stupid. I'll double-check.
     
  4. Daerst

    Daerst

    Joined:
    Jun 16, 2016
    Posts:
    275
    The issue is that PlayOneShot does not count as a reference to the AudioClip. If the last Unity Object that holds a reference to the Clip is destroyed, the clip will get unloaded and cut off. Somebody already mentioned a similar thing 10 years ago here: https://forum.unity.com/threads/playoneshot-and-resources-unloadunusedassets.97667/

    There doesn't seem to be any open bug related to this, so I will report it and link it here soon. For the time being, I will probably work around this by instantiating my own pooled AudioSources (DontDestroyOnLoad) which then hold the reference as long as the clip is playing.
     
  5. Daerst

    Daerst

    Joined:
    Jun 16, 2016
    Posts:
    275
    Can you believe it?

    Code (CSharp):
    1. [RequireComponent(typeof(AudioSource))]
    2. public class GlobalAudio : MonoBehaviour
    3. {
    4.     [SerializeField] private AudioSource _audioSource = null;
    5.  
    6.     public void PlayOneShot(AudioClip clip)
    7.     {
    8.         _audioSource.PlayOneShot(clip);
    9.         StartCoroutine(HoldHostage(clip));
    10.     }
    11.  
    12.     private IEnumerator HoldHostage(AudioClip clip)
    13.     {
    14.         yield return new WaitForSeconds(clip.length + 1.0f);
    15.     }
    16. }
     
  6. bakioztepe

    bakioztepe

    Joined:
    Sep 23, 2019
    Posts:
    9
    Interesting however makes sense. This is probably by design.

    You can't expect AudioClip to hold references under the hood because you can call PlayOneShot() multiple times, in parallel.

    You can solve it by creating a persistent object, that has a script which references these clips.

    Or you can load the clips using Resources.Load and store the loaded clips in a static class or singleton object.
     
  7. Daerst

    Daerst

    Joined:
    Jun 16, 2016
    Posts:
    275
    Yep, and each OneShot should increase the reference count by one and decrease it when it's done playing. I'd definitely expect this to happen under the hood. Anyway, worked around it, time to move on :)
     
  8. Daerst

    Daerst

    Joined:
    Jun 16, 2016
    Posts:
    275