Search Unity

Bug AudioClip.Length is incorrect when loading from WebRequest GetAudioClip

Discussion in 'Audio & Video' started by ickydime, Mar 25, 2021.

  1. ickydime

    ickydime

    Joined:
    Nov 20, 2012
    Posts:
    110
    I think this is a potential bug to report, but I want to sanity check that I am not doing anything wrong first.

    I have a bunch of mp3 files in the StreamingAssets folder (trying to keep the build size down for Android).

    When I load them via:


    Code (CSharp):
    1. var webRequest = UnityWebRequestMultimedia.GetAudioClip(fileUrl, AudioType.MPEG);
    2.             yield return webRequest.SendWebRequest();
    The clip length is 2x the actual length.

    When I put them in Resources and load via:
    Code (CSharp):
    1.  var clip = Resources.Load<AudioClip>(fileUrl.Substring(0, fileUrl.Length-4));
    The clip length is correct.

    I've tried AudioType.MPEG and AudioType.UNKNOWN.

    I've tried to sequence these audio clips by either checking clip.length and waiting that amount of time or by checking AudioSource.IsPlaying but even the IsPlaying returns true for the double amount.

    Sooooo. Is this a bug? Should I be using a different method here either for loading or for storing?

    I've attached a zip file of the mp3 in case the compression/etc isn't supported. It comes up as Vorbis under Unity's compression format.
     

    Attached Files:

    achimmihca likes this.
  2. cova8bitdots

    cova8bitdots

    Joined:
    Sep 30, 2019
    Posts:
    8
    I also face same issue.
    I try to download audioclip via UnityWebRequestMultimedia.GetAudioClip
    The result of AudioClip.samples and AudioClip.length are twice than those that I expected.

    It seems that this behaviour is WebRequest Bug.

    Code (CSharp):
    1.  public static async UniTask<AudioClip> GetAudioClipFromWWW(string uri, CancellationToken token = default)
    2.         {
    3.             AudioType type = AudioType.WAV;
    4.             if (uri.Contains(".ogg"))
    5.             {
    6.                 type = AudioType.OGGVORBIS;
    7.             }
    8.             else if (uri.Contains(".mp3"))
    9.             {
    10.                 type = AudioType.MPEG;
    11.             }
    12.  
    13.             using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(uri, type))
    14.             {
    15.                 await www.SendWebRequest();
    16.                 if (www.isNetworkError || www.isHttpError )
    17.                 {
    18.                     Debug.Log(www.error);
    19.                     return null;
    20.                 }
    21.                 else
    22.                 {
    23.                     AudioClip myClip = DownloadHandlerAudioClip.GetContent(www);
    24.                     Debug.Log(
    25.                         $"[Audio] ClipData Fs:{myClip.frequency}[Hz], {myClip.channels}[ch] Sample:{myClip.samples}, Len:{myClip.length}");
    26.                     return myClip;
    27.                 }
    28.             }
    29.          
    30.         }
    This bug can be reproduced Unity2019.4.9f1 and Unity2018.4.22f1
     
  3. UnityMaru

    UnityMaru

    Community Engagement Manager PSM

    Joined:
    Mar 16, 2016
    Posts:
    1,227
    Hey folks,

    We'd suggest making a bug report on this issue so the team can begin the process of looking into this for you :) Let me know the bug report ID so I can flag internally.

    https://unity3d.com/unity/qa/bug-reporting
     
  4. cova8bitdots

    cova8bitdots

    Joined:
    Sep 30, 2019
    Posts:
    8
  5. gdosu

    gdosu

    Joined:
    Aug 24, 2020
    Posts:
    13
    Same Issue on 2020.3.15f2 and 2020.3.16f1.
     
  6. DaveA_VR

    DaveA_VR

    Joined:
    May 26, 2022
    Posts:
    35
    I'm seeing lenth = zero in 2021.3.0f1
     
  7. FGFFFF00

    FGFFFF00

    Joined:
    Oct 9, 2020
    Posts:
    2
    same in 2020.3.30f1
     
  8. ickydime

    ickydime

    Joined:
    Nov 20, 2012
    Posts:
    110
    This bug is still active and its fun to deal with. I had to go back into the project and update some audio files. Seems as though the updated files are not double length but the old ones are and I'm not sure what is difference as the frequency/channels are the same. Bitrate on the mp3 files are different so that could be something to do with it? Just not sure how to catch that on the unity side as all properties seem to be the same.

    https://issuetracker.unity3d.com/is...imedia-dot-getaudioclip-from-firebase-storage
     
  9. ThendonExe

    ThendonExe

    Joined:
    Feb 27, 2019
    Posts:
    6
    for me in 2021.2.3f1 the length seems to be roughly 1/3rd of the source file
     
  10. achimmihca

    achimmihca

    Joined:
    Feb 13, 2016
    Posts:
    280
    Last edited: Jul 13, 2023
    DaveA_VR likes this.
  11. GleetchDev

    GleetchDev

    Joined:
    Mar 18, 2021
    Posts:
    8
    Just discovered this bug in 2022.3.4f1

    The generated audioclip Lenght and Samples value is always 0 on the WebGL build
     
    Last edited: Jul 14, 2023
  12. achimmihca

    achimmihca

    Joined:
    Feb 13, 2016
    Posts:
    280
    > Will open a new bug report.

    Unity just confirmed the bug (IN-47586). Hopefully they will fix it in a future release.
     
  13. SeventhString

    SeventhString

    Unity Technologies

    Joined:
    Jan 12, 2023
    Posts:
    410
    I recently fixed this bug, it should makes it way soon in the latest and LTS versions.

    It was a fun weird ass codec bug...

    Cheers!
     
    akingdom and achimmihca like this.
  14. Ordinary1107

    Ordinary1107

    Joined:
    May 24, 2020
    Posts:
    1
    You are a savior. I had fixed this manually, but I faced another issue.

    Code (CSharp):
    1. public IEnumerator GetAudioClipUniversal(string fullPath, float percentageOffset, bool isLooping, bool playImmediately)
    2.     {
    3.         using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip($"file://{fullPath}", AudioType.MPEG))
    4.         {
    5.             yield return www.SendWebRequest();
    6.  
    7.             if (www.error == null)
    8.             {
    9.                 UnloadMainSong();
    10.                 song = DownloadHandlerAudioClip.GetContent(www);
    11.                 int channels = song.channels;
    12.                 int frequency = song.frequency;
    13.                 float[] allSamples = new float[song.samples * channels];
    14.                 song.GetData(allSamples, 0);
    15.                 song.UnloadAudioData();
    16.  
    17.                 // Audio clip is downloaded with a lot of leading zeros, we remove them manually...
    18.                 int lastIndex = Array.FindLastIndex(allSamples, b => b != 0);
    19.                 song = AudioClip.Create("song2", (lastIndex + 1) / channels, channels, frequency, false);
    20.                 song.SetData(allSamples[0..lastIndex], 0);

    Turns out creating float[] array = new float[size] creates "Empty fragmented heap space" that does not free up. So every time I load a song, around 100Mb of RAM is lost, after a handful song loads I run out of RAM and app crashes... I'll take a break and wait for the update to roll out.
     
    Last edited: Jul 23, 2023
  15. AlmazAppStudio

    AlmazAppStudio

    Joined:
    Feb 7, 2021
    Posts:
    1
    Were you able to fix it? I came to the conclusion that the problem is in the audio files themselves. But of course, Unity also does not work correctly.
     
  16. SeventhString

    SeventhString

    Unity Technologies

    Joined:
    Jan 12, 2023
    Posts:
    410
    This feels like a garbage collecting issue. Maybe you could TRY to run `GC.Collect()` to clean it up, but I don't think that would be a sustainable solution as this could be a stalling kick in the nuts of your main thread, depending of the amount of work it would have to do then.

    I'm not aware of your loading strategy, but ideally I'd have the mp3 serialized (aka already managed by unity as an asset) and configure it as `Streaming` or maybe even something like this:

    Code (CSharp):
    1. AudioClip myClip = Resources.Load<AudioClip>("MyAudioClip");
    2. myClip.loadType = AudioClipLoadType.Streaming;
    3. myClip.LoadAudioData();
     
  17. cgbrown-mos

    cgbrown-mos

    Joined:
    Oct 17, 2014
    Posts:
    9
    I had a similar issue using MP3 files, but it turns out that it was caused by using a variable bitrate encoding. Re-encoding using a constant bitrate fixed the issue. I know this is mentioned in other threads on this forum, but just posting here in case anyone else finds this thread looking for answers with the same issue I had.
     
  18. jasonkappes656

    jasonkappes656

    Joined:
    Aug 8, 2021
    Posts:
    5
    I managed to find a workaround to this bug. I had the issue where the end of my .mp3 file was being cut off by 'UnityWebRequestMultimedia.GetAudioClip(mp3audioPath, AudioType.MPEG)'

    Using the more primitive method from this forum post worked for me: https://forum.unity.com/threads/how...and-make-it-stay-compressed-in-memory.960910/

    Here's a code example of the solution. In GetMp3Audio I pass it the data for the mp3 then I load it and I can confirm it plays the entire mp3 correctly.

     public void GetMp3Audio(byte[] mp3Audio)
    {
    string filePath = System.IO.Path.Combine(Application.persistentDataPath, "output.mp3");
    System.IO.File.WriteAllBytes(filePath, mp3Audio);
    var path = "file:///" + Application.persistentDataPath + "/output.mp3";
    StartCoroutine(PlayDownloadedAudio(path));
    }

    private IEnumerator PlayDownloadedAudio(string mp3audioPath)
    {
    var dh = new DownloadHandlerAudioClip(mp3audioPath, AudioType.MPEG);
    dh.compressed = true;
    using (UnityWebRequest wr = new UnityWebRequest(mp3audioPath, "GET", dh, null))
    {
    yield return wr.SendWebRequest();
    if (wr.responseCode == 200)
    {
    PlayClip(dh.audioClip);
    }
    else
    {
    Debug.LogError("Error");
    }
    }
    }


    I was stuck on this for hours, so hoping it helps someone :) P.S. If you use Play.HT this is the solution you should use after downloading their audio.

    Using 2022.1.23f1
     
    tony_bean_dong likes this.
  19. akingdom

    akingdom

    Joined:
    Mar 30, 2013
    Posts:
    15
    I'm still seeing this behaviour in 2023.1.3f1. Which version did the fix go live in? Thanks :)
     
  20. SeventhString

    SeventhString

    Unity Technologies

    Joined:
    Jan 12, 2023
    Posts:
    410
    From what I see it has landed in a yet unreleased version (2023.2.xyz) and backports have not started yet. I implore your patience, as it should be available Soon™.
     
  21. akingdom

    akingdom

    Joined:
    Mar 30, 2013
    Posts:
    15
    Thanks for taking time to respond. Much appreciated.

    At present I've hacked a workaround of multipying the length * 0.5f for a list of all my audio files known to have this issue, since I already know what files I'm playing. I mention this in case it helps others.
     
  22. SeventhString

    SeventhString

    Unity Technologies

    Joined:
    Jan 12, 2023
    Posts:
    410
    Be careful with that, as it might not fix the problem every time. The cause problem is that, in the MP3 format, the "bitrate" can vary, even with CBR files (Constant Bit Rate) because of something called "bit reservoir" that allows for increased resolution on transients.

    Now that's the CAUSE of the problem (variable bit rate). Now, since it's a video game engine and that everything has to be lightning fast, shortcuts are used. In this case, the shortcut is that we evaluate the length on the file based on the bitrate and the number of frames of the file and we (used to) only read the first frame's bitrate rather than parsing every frame to have the exact duration of the file.

    The very best workaround is simply to use a different source file format, such as ogg/vorbis.

    Cheers!
     
  23. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    1,162
    Not sure this related. But if I load mp3 in editor and call Play before LoadAudioData, the editor will just crash

    2023.2.2f1
     
  24. achimmihca

    achimmihca

    Joined:
    Feb 13, 2016
    Posts:
    280
    I can confirm the issue has been fixed in Unity 2023.2.3f1 whereas I can still reproduce it in Unity 2022.3.9f1.

    Note that the length is still not perfect, but much better. For example, for a 4 seconds mp3 it now returns 4.153 (roughly the correct length)
    seconds, whereas before it returned 8.202 seconds (roughly double the length).

    For details, see my test repo: https://github.com/achimmihca/UnityAudioClipMp3WrongDuration
     
    SeventhString likes this.
  25. SeventhString

    SeventhString

    Unity Technologies

    Joined:
    Jan 12, 2023
    Posts:
    410
    I want to point that the length given there is an approximation. For the sake of performance, this codec estimates the length by inspecting ONLY the first few frames of the file, rather than going through each of them and accumulating an exact value depending on each frames bitrate.
    Previously it was only looking at the first 4kB, which led to bad estimations since the bitrate of these early frame could be skewed for various reasons, notably this interesting thing called "bit reservoir".
     
  26. dhtpdud528

    dhtpdud528

    Joined:
    Apr 8, 2018
    Posts:
    23
    This issue still occurs in 2022.3.20f1 and 2023.2.10f1

    This is the code I used.
    Code (CSharp):
    1. public static async UniTask<AudioClip> GetAudioFile(string url, AudioType audioType)
    2. {
    3.     if (url.Equals(null) || url.Equals("")) return null;
    4.     if (!url.Substring(0, 4).Equals("http"))
    5.         url = $"file://{url}";
    6.     //Debug.Log($"GetAudioFile({url})");
    7.     using (UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(url, audioType))
    8.     {
    9.         await request.SendWebRequest();
    10.         if (request.result == UnityWebRequest.Result.ConnectionError)
    11.         {
    12.             Debug.LogError(request.error);
    13.             return null;
    14.         }
    15.  
    16.         return DownloadHandlerAudioClip.GetContent(request);
    17.     }
    18. }
    Code (CSharp):
    1. audioSource.clip = await MyUtils.GetAudioFile(audioUrl, AudioType.WAV);
    In Editor ,Windows, OSX is fine.
    Play well, and normal audioSource.clip.length has returned.

    And also, in WebGL build play well.
    but audioSource.clip.length keep return 0.

    I was upgrade my project to 2023.2.10f1 but it still hasn't been resolved.
     
    Last edited: Feb 16, 2024
  27. dhtpdud528

    dhtpdud528

    Joined:
    Apr 8, 2018
    Posts:
    23
    ok i just found something in web console (2023.2.3f1 WebGL build)
    Code (CSharp):
    1. Trying to get length of sound which is not loaded.
    And I can't find solution anywhere about this.
     
  28. dhtpdud528

    dhtpdud528

    Joined:
    Apr 8, 2018
    Posts:
    23
    Sloved

    Code (CSharp):
    1. using (UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(url, audioType))
    2. {
    3.     await request.SendWebRequest();
    4.     if (request.result == UnityWebRequest.Result.ConnectionError)
    5.     {
    6.         Debug.LogError(request.error);
    7.         return null;
    8.     }
    9.     var clip = DownloadHandlerAudioClip.GetContent(request);
    10.     await UniTask.WaitUntil(() => clip.loadState == AudioDataLoadState.Loaded);
    11.     return clip;
    12. }
    The key is
    loadState


    We hav to wait until the
    clip.loadState
    to be
    AudioDataLoadState.Loaded
    .
     
    Last edited: Feb 17, 2024
    SeventhString likes this.