2

I've got this code within an IEnumerator, and it's working perfectly well if I use a properly formatted wav file. But the files I'm loading are user-submitted, so I want to handle improperly formatted wav files. I made a 0-length text file and renamed it to appear like a wav file, and once the code reaches the "DownloadHandlerAudioClip.GetContent" call the app crashes with the following error:

Error: Cannot create FMOD::Sound instance for clip "" (FMOD error: Unsupported file or audio format. ) UnityEngine.Networking.DownloadHandlerAudioClip:GetContent (UnityEngine.Networking.UnityWebRequest) XMLFrobnicator/d__12:MoveNext () (at Assets/Scripts/XMLFrobnicator.cs:197) UnityEngine.SetupCoroutine:InvokeMoveNext (System.Collections.IEnumerator,intptr)

So it's not an Exception, otherwise the try/catch would catch it. Is there another way to catch this sort of thing? My friend suggested spawning another process, but I don't know if that's even possible with Unity. If I can't catch it, can I somehow test to see if the content of the UnityWebRequest is a valid wav file?

Here's my code:

    using (UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip(fileName, AudioType.WAV)) {
        yield return uwr.SendWebRequest();
        if(uwr.result != UnityWebRequest.Result.Success) {
            Debug.Log(uwr.error);
            yield break;
        }
        else {
            try {
                app.levelMusic = DownloadHandlerAudioClip.GetContent(uwr);
            }
            catch(System.Exception e) {
                Debug.Log(e);
                yield break;
            }
        }
    }
Cassandra Gelvin
  • 225
  • 1
  • 3
  • 10
  • The error is: System.ArgumentException: The file is not a valid wave file. at UnityEngine.Networking.DownloadHandlerAudioClip.GetContent (UnityEngine.Networking.UnityWebRequest www) [0x00027] in <7ccb50d332e14f0ebcf2ab7bd33c6eaa>:0 at LevelEditor+d__2.MoveNext () [0x0006e] in :0 – Ogunleye Olawale Jan 21 '23 at 23:23
  • I've tried to check the file type and only proceed with the code if the file is a valid wav file, but I haven't been able to get that to work. Is there any way to handle improperly formatted wav files in this code? – Ogunleye Olawale Jan 21 '23 at 23:23
  • Check its not 0 length? – BugFinder Jan 21 '23 at 23:41
  • Your best bet is to not consider that as a .WAV file in first instance but as a binary file instead. Then write your own .WAV reader and produce an AudioClip out of it, this should be relatively easy. – aybe Jan 21 '23 at 23:48
  • @OgunleyeOlawaleLawrence I'm not sure what you mean. Where are you getting that error? And basically, if I'm unable to load an improperly formatted wav file, I'm planning on just ignoring it and not trying to load it (it is supposed to be background music so it's not important). – Cassandra Gelvin Jan 22 '23 at 00:26
  • @BugFinder That will only detect the case where it's a 0-length file. What if it's, I don't know, a jpg image of a duck that's been renamed as a wav file? That's also invalid. – Cassandra Gelvin Jan 22 '23 at 00:27
  • @aybe From my brief research, creating my own .WAV reader does not seem easy at all. Do you have any suggestions for resources to accomplish this? – Cassandra Gelvin Jan 22 '23 at 00:46
  • Well wav files have headers. You could read it and check. I suggested test for zero as you said you were sensing zero length files. – BugFinder Jan 22 '23 at 01:00
  • @CassandraGelvin Providing that all you'd have to support is plain PCM (vast majority) it isn't difficult at all, some good specs https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html. All you have to do once you've parsed the RIFF headers is to convert samples to floats. Alternatively, if you don't want to, use another library, e.g. Un4seen BASS or NAudio for instance, they would do all the heavy lifting and potentially handle faulty WAVs as well. The former supports Unity, the latter I'm not sure. If that fails, write your reader, do unit tests, it's not an impossible task. – aybe Jan 22 '23 at 02:42
  • Also, before potentially wasting your time, try to play that WAV file on some popular players to assert that indeed it is playable beside the fact that Unity chokes on it. If it isn't then it's most probably unrecoverable (unless it's really important and you have lot of time). Last thing, keep in mind that audio clips are quite limited programmatically, e.g. if you need loop points, you're screwed basically as it's not possible to create some from code, etc. – aybe Jan 22 '23 at 02:51
  • I think [`DownloadHandlerAudioClip.GetContent`](https://docs.unity3d.com/ScriptReference/Networking.DownloadHandlerAudioClip.GetContent.html) is supposed to return `null` if it cannot create an [`AudioClip`](https://docs.unity3d.com/ScriptReference/AudioClip.html) from the data. In which case have you tried wrapping `app.levelMusic` in an `if`? – fdcpp Jan 22 '23 at 15:35
  • Or better yet, assign the result to a variable and test it _before_ assigning to `app.levelMusic` – fdcpp Jan 22 '23 at 16:59
  • Or check [the AudioClip property](https://docs.unity3d.com/ScriptReference/Networking.DownloadHandlerAudioClip-audioClip.html) after the GET request – fdcpp Jan 22 '23 at 17:01
  • In case anyone is curious, I realized that I was misinterpreting what was happening. It wasn't actually crashing, just using the Debug.Error and my editor was set to "Error Pause" so it would stop when it happened, which I had only previously experienced with Exceptions. – Cassandra Gelvin Jan 30 '23 at 19:34

1 Answers1

0

If it's just to handle your response you won't have any problem ignoring it , the try and catch will work fine. Try this out and tell us the result this time

StartCoroutine(GetAudioClip());
IEnumerator GetAudioClip()
    {
    try { 
       using (UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip(fileName, AudioType.WAV)) {
            yield return uwr.SendWebRequest();
           if (uwr.result == UnityWebRequest.Result.ConnectionError)
            {
                Debug.Log(uwr.error);
            }
            else
            {
                AudioClip myClip = DownloadHandlerAudioClip.GetContent(uwr);
                app.levelMusic = myClip;
            }
        }
    }
       catch(Exception e) {
                    Debug.Log(e.message);
                    yield break;
                }
}
thunderkill
  • 126
  • 5
  • As is, this didn't compile. You can't use a "yield" statement inside a "try" block with a "catch". I tried rewriting it, but I still got the same error, which is not being caught. The error has to be on the line "AudioClip myClip = DownloadHandlerAudioClip.GetContent(uwr);", which is still inside the try-catch block. I would paste my new code but I don't think I have enough characters. – Cassandra Gelvin Jan 25 '23 at 20:53
  • @CassandraGelvin this is my discord contact DainRedBeard#8847 if you like send me here we will review it together yes ? – thunderkill Jan 26 '23 at 07:28
  • and for my code I must apologise I left the return part for you to handle what do you need to return is up to you – thunderkill Jan 26 '23 at 07:29