Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question How do you upload an AudioClip to a server using UnityWebRequest?

Discussion in 'Scripting' started by cadburia, Jan 4, 2023.

  1. cadburia

    cadburia

    Joined:
    Sep 22, 2022
    Posts:
    9
    My current approach is to take an AudioClip, turn it into a byte array, then put it into an UploadHandler, attached to a UnityWebRequest, to send a POST request to a server.

    Right now, when I pass through an AudioClip to my ConvertAudioToByteArray() function I essentially get back a byte array full of NULL characters. This seems to happen when I use the GetData method on the clip parameter, as a bunch of 0s print out when I Debug.Log the foreach loop of floatArrayOfClip. When I send out a post request to my dev server I get a ProtocolError on the client side.

    I believe I have tested everything. The audioClip argument is a microphone recording and is working correctly. Dev server is working correctly. The program is connecting successfully to the dev server.

    Using Unity 2021.3.

    Thanks in advance.
    Code (CSharp):
    1. public void initiateCoroutine(AudioClip audioClip)
    2. {
    3.    StartCoroutine(postRequest(audioClip));
    4. }
    5.  
    6. IEnumerator postRequest(AudioClip audioClip)
    7. {
    8.    // convert audio to byte array
    9.    byte[] byteArray = ConvertAudioToByteArray(audioClip);
    10.  
    11.    // create UWW and handler, and attach handler to UWW
    12.    UnityWebRequest uwr = new UnityWebRequest("-CORRECT URI-", "POST");
    13.    UploadHandler uploader = new UploadHandlerRaw(byteArray);
    14.    uwr.uploadHandler = uploader;
    15.  
    16.    yield return uwr.SendWebRequest();
    17.  
    18.    if (uwr.result == UnityWebRequest.Result.ConnectionError)
    19.    {
    20.        Debug.Log(uwr.error);
    21.    }
    22.    else if (uwr.result == UnityWebRequest.Result.ProtocolError)
    23.    {
    24.        Debug.Log(uwr.error);
    25.        Debug.Log("PROTOCOL");
    26.    }
    27.    else if (uwr.result == UnityWebRequest.Result.DataProcessingError)
    28.    {
    29.        Debug.Log(uwr.error);
    30.        Debug.Log("PROCESSING");
    31.    }
    32.    else
    33.    {
    34.        Debug.Log(uwr.result);
    35.        Debug.Log(uwr.downloadHandler.text);
    36.    }
    37. }
    38.  
    39. private static byte[] ConvertAudioToByteArray(AudioClip clip)
    40. {
    41.    // get user recording and convert user recording into a float array
    42.    var floatArrayOfAudioClip = new float[clip.samples];
    43.    clip.GetData(floatArrayOfAudioClip, 0);
    44.  
    45.    // Create buffer stream
    46.    MemoryStream stream = new MemoryStream();
    47.    BinaryWriter writer = new BinaryWriter(stream);
    48.  
    49.    // Populate audio clip floats into buffer stream
    50.    foreach (var sample in floatArrayOfAudioClip)
    51.    {
    52.        writer.Write(sample);
    53.    }
    54.  
    55.    byte[] bytes = stream.ToArray();
    56.  
    57.    return bytes;
    58. }
     
  2. TzuriTeshuba

    TzuriTeshuba

    Joined:
    Aug 6, 2019
    Posts:
    185
    From unity's docs at https://docs.unity3d.com/ScriptReference/AudioClip.GetData.html

    "Note that with compressed audio files, the sample data can only be retrieved when the Load Type is set to Decompress on Load in the audio importer. If this is not the case then the array will be returned with zeroes for all the sample values."
     
  3. cadburia

    cadburia

    Joined:
    Sep 22, 2022
    Posts:
    9
    Thanks, Tzuri. How would I implement this with user-generated microphone recordings, as no files are being loaded into memory?
     
  4. TzuriTeshuba

    TzuriTeshuba

    Joined:
    Aug 6, 2019
    Posts:
    185
    I dont really know honestly or i would have been happy to give you my code. I cant even claim with certainty that your audio clip is compressed, but if it were, that would explain it. I imagine playing with the fields that relate to compression would solve it if so.

    https://docs.unity3d.com/Manual/class-AudioClip.html
    https://docs.unity3d.com/ScriptReference/AudioClip.html

    how do you record the audioClip to begin with? I imagine there's a good chance that you can provide an arguement there that wont compress it maybe. there's also audioClip.loadType and audioClip.LoadAudioData(), but i dont know how relevent they are for your issue.
     
  5. cadburia

    cadburia

    Joined:
    Sep 22, 2022
    Posts:
    9
    The audioClip is recorded with a VR headset (Oculus Quest 2) using the Microphone class, which does not have an associated inspector component where I could modify compression/load settings (as far as I am aware). I guess I could save it to a file and then just read the bytes out of the file, but I am trying to use a solution that avoids I/O operations if at all possible.
     
  6. TzuriTeshuba

    TzuriTeshuba

    Joined:
    Aug 6, 2019
    Posts:
    185
    And if you play the clip on the client side after Microphone.End(), does it play as expected?

    I found this:
    https://forum.unity.com/threads/microphone-network-test.123776/
    may have some useful info.

    Id check that all is as expected client side first. See That GetData isnt giving you all zeros. See that playng the clip sounds right. see that the loadState is good.

    Sorry i couldnt help much :/
     
  7. cadburia

    cadburia

    Joined:
    Sep 22, 2022
    Posts:
    9
    Yeah, the microphone works fine and any associated audio clip works as well. I think the problem is what you highlighted with your first post, GetData won't fetch values in compressed AudioClips. It looks like microphone files are .ogg.
     
    TzuriTeshuba likes this.