Search Unity

Handling AudioClip loading / When to Unload AudioClips?

Discussion in 'Addressables' started by AwesomeX, Dec 10, 2019.

  1. AwesomeX

    AwesomeX

    Joined:
    Sep 10, 2013
    Posts:
    115
    I'm new to Addressables and I'm looking for info on how I'd go about loading audioclips at runtime.
    I have an AudioManager class that handles playing clips via an addressable URL or an assetreference of an audioclip.

    My main question is when/how do I handle releasing/unloading the audioclip properly?

    With the example code below the audio all plays properly when called, but it's a bit confusing because I'm releasing the obj at the same time.

    Code (CSharp):
    1.     public static void PlaySound(string URL, Vector3 position)
    2.     {
    3.         Addressables.LoadAssetAsync<AudioClip>(URL).Completed += (obj) =>
    4.         {
    5.             AudioClip audioClip = obj.Result;
    6.  
    7.             if (audioClip == null)
    8.             {
    9.                 Debug.LogWarning("<color=#FF7777>Audio Manager: Missing sound " + URL + "</color>");
    10.                 return;
    11.             }
    12.  
    13.             Debug.Log("<color=#ffb3ff>Audio Manager: Playing sound " + audioClip.name + " - " + URL + "</color>");
    14.             PlaySound(audioClip, position);
    15.  
    16.             Addressables.Release(obj);
    17.         };
    18.     }
    I'd also like to know if how I'm handling loading audioclips is completely trash or not.
    Overall info would be great. Thanks.
     
  2. AwesomeX

    AwesomeX

    Joined:
    Sep 10, 2013
    Posts:
    115
    Still looking for info on when it's an appropriate time to release an audioclip. Right away, when the clip is done playing? Some other way? And what's the difference.
     
  3. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    Pretty sure it's not going to release if it's still being used. After all "release" should reclaim the memory and if it's being used that's impossible. Hopefully someone will answer soon.
     
  4. VaygrEmpire

    VaygrEmpire

    Joined:
    Sep 30, 2016
    Posts:
    40
  5. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    Well it looked promising, but I found that even with his exact example - I profiled it, and the audio memory indeed *does not* get released as he claims, at least according to the profiler. Not on the audio or memory profiler. I tried even going GC.Collect and yielding Resources.UnloadUnusedAssets. It worked 1 time but usually not.

    So I'm still stuck on this. Hopefully someone from Unity will see this thread and tell us the right way to do it. Or that it's broken (bug)?
     
    Last edited: Dec 15, 2019
  6. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    I had a brief Skype with the author of that post, from the Netherlands, and we figured it all out. The Profiler running in the Editor isn't so great and accurate, and I had to build the Addressable group in the Editor, but finally we got it to show properly. If you Profile on a device you'll see it works properly.
     
  7. caochao88_unity

    caochao88_unity

    Joined:
    May 16, 2019
    Posts:
    26
    I’m very confused about Addressable.Release. I can play audioclip even it has been released.
    e.g.:
    var clip = await Addressables.LoadAssetAsync<AudioClip>(addressOfAudioClip).Task;
    audioSource.clip = clip;
    Addressables.Release(clip);
    audioSource.Play();
     
    Last edited: Mar 17, 2020
  8. caochao88_unity

    caochao88_unity

    Joined:
    May 16, 2019
    Posts:
    26
    I’m very confused about Addressable.Release. I can play audioclip even it has been released.
    e.g.:
    var clip = await Addressables.LoadAssetAsync<AudioClip>(addressOfAudioClip).Task;
    audioSource.clip = clip;
    Addressables.Release(clip);
    audioSource.Play();

    correction: after many experiments,I found audioSource can't play after releasing audioclip if set play mode script to using exsting build.
     
    Last edited: Mar 17, 2020
  9. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    For calling Addressable.Relesae to free up any memory, you first have to get rid of all instances of it.

    i.e. play the audio, then set AudioSource.clip = null.

    Then you may be able to release it and get the memory back.
     
  10. Michal_Stangel

    Michal_Stangel

    Joined:
    Apr 17, 2017
    Posts:
    151
    How do you guys technically check if audio clip has been already played and can be released? All in one coroutine?
     
  11. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    You don't need to release in edit mode is my understanding, just like Resources.Load.

    If you're asking about during Play mode, it's quite complicated. Not a couroutine, but when the audio source is stopped, we remove it from "active instances" and if that's the last instance of that clip we unload it from Addressable. Basically you need to track the active instances yourself. There's nothing built it that you can query.
     
  12. Michal_Stangel

    Michal_Stangel

    Joined:
    Apr 17, 2017
    Posts:
    151
    Thanks Brian.

    I ended up remembering every runtime loaded audio clip, it's audio source and Addressables loading handle. At the end of the turn (turn based game) I check list which stores these infos and if audio source is null, doesn't play or play different clip (name comparison) I release audio clip from memory (nulling clip and Release stored handle).

    But, even if Addressables Event Viewer shows clip is unloaded, it still resides in memory and I have no idea what to do with it. Clip is not part of any Asset bundle. I also tried to change settings for Addressables Group where I have audio clips to Pack separately if it may help. But no luck.
     

    Attached Files:

  13. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    The profiler in-editor doesn't always work properly. I suggest profiling it on-device, if you haven't tried that.
     
  14. Michal_Stangel

    Michal_Stangel

    Joined:
    Apr 17, 2017
    Posts:
    151
    It was the same in built app. But i figured it out at last. Problem was that one audio clip was part of the same Addressables Group and was referenced in preloaded particle effect. And if one asset in Asset bundle (Group) is still referenced, nothing else from bundle can be unloaded. It's tricky :)
     
  15. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    Correct, glad you figured it out!
     
  16. crawfis

    crawfis

    Joined:
    Jan 30, 2014
    Posts:
    114
    Wooh!!! Help me understand that. I have an Addressable group with over 1GB of music in it. I am releasing the handles after a song finishes (and after setting the clip of the audio source to null). I always have on song playing from the group. The memory only releases if I Stop all music. So you are saying as long as I am playing music the memory will go up. I guess I could break the songs into different groups. I am shocked if this is the behavior and sounds like a bug! Is this true for all types of assets?
     
    Last edited: Dec 12, 2020
  17. Michal_Stangel

    Michal_Stangel

    Joined:
    Apr 17, 2017
    Posts:
    151
    From what I've red and tried it works like that. Addressable groups are basically asset bundles and if anything from asset bundle is still in use it cannot be unloaded from memory. Specifically for music I separated all my tracks into several Groups for different game situations. So it should not hold too much of them in the memory.
    Anyway, in Groups settings there is an option called Bundle Mode and you can select "Pack separately". I suppose this should alter this behaviour. But for some reason it didn't work for me when I tried several months ago. Something like I cannot even build the game, not sure. Please let me know if you will investigate it :)
     
  18. crawfis

    crawfis

    Joined:
    Jan 30, 2014
    Posts:
    114
    Thanks Michal. Afraid to touch anything now that I have it working. If I hit stop, it releases the clip and handle and immediately cleans up the memory. Trying to have everything cross-fade thus must be the problem as one soundtrack is always playing. I will try having two groups and cross-fading between them. Right now no real controls on the playtrack selection in my games, just random. Will research "Pack separately" in my spare time.
     
  19. calpolican

    calpolican

    Joined:
    Feb 2, 2015
    Posts:
    425
    Sorry to necro this post, but I'm having the same issue and I want to know if anyone find a better way, and if not if you can share more insight on how you're doing this.
    I'm always amazed that there's no event that tells you if a clip has finish playing. Now on top of solving that I also need to get a hold of the addressable handle and keep it store?... and also, if I have a bunch of gui sounds, just using one will load everyone into memory? Sorry if I sound repetitive, but after one year and a half, have you guys found more info on this? Sounds like using a coroutine for sounds will be better, although it does sound a bit like a mess.
     
  20. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    There really should be some events on the AudioSource you can hook into. That would make things easier.
     
  21. calpolican

    calpolican

    Joined:
    Feb 2, 2015
    Posts:
    425
    Maybe using extension methods for loading and stopping that also make sure to release the asset (??)

    Code (CSharp):
    1.     public static void StopAndUnload(this AudioSource source)
    2.     {
    3.         source.Stop ();
    4.        if (source.clip != null) { Addressables.Release (source.clip); source.clip = null; }// release
    5.     }
    6.  
    7.     //When you load the reference you check if a clip was there, it there was a clip there, you realease it and then you load the new clip.
    8.     public static void LoadAddressableClip (this AudioSource source, AssetReference reference)
    9.     {
    10.         if (reference.RuntimeKeyIsValid ()) { Addressables.LoadAssetAsync<AudioClip> (reference).Completed += x => { if (source.clip != null) { Addressables.Release (source.clip); }source.clip = x.Result; source.Play (); }; } //Release previous clip before loading new one.
    11.     }
    Stil, I don't think that's properly unloading the file.
    And, do I really need an asset group for every sound?
     
    Last edited: Jul 30, 2021