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

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.

public void initiateCoroutine(AudioClip audioClip)
{
   StartCoroutine(postRequest(audioClip));
}

IEnumerator postRequest(AudioClip audioClip)
{
   // convert audio to byte array
   byte[] byteArray = ConvertAudioToByteArray(audioClip);

   // create UWW and handler, and attach handler to UWW
   UnityWebRequest uwr = new UnityWebRequest("-CORRECT URI-", "POST");
   UploadHandler uploader = new UploadHandlerRaw(byteArray);
   uwr.uploadHandler = uploader;

   yield return uwr.SendWebRequest();

   if (uwr.result == UnityWebRequest.Result.ConnectionError)
   {
       Debug.Log(uwr.error);
   }
   else if (uwr.result == UnityWebRequest.Result.ProtocolError)
   {
       Debug.Log(uwr.error);
       Debug.Log("PROTOCOL");
   }
   else if (uwr.result == UnityWebRequest.Result.DataProcessingError)
   {
       Debug.Log(uwr.error);
       Debug.Log("PROCESSING");
   }
   else
   {
       Debug.Log(uwr.result);
       Debug.Log(uwr.downloadHandler.text);
   }
}

private static byte[] ConvertAudioToByteArray(AudioClip clip)
{
   // get user recording and convert user recording into a float array
   var floatArrayOfAudioClip = new float[clip.samples];
   clip.GetData(floatArrayOfAudioClip, 0);

   // Create buffer stream
   MemoryStream stream = new MemoryStream();
   BinaryWriter writer = new BinaryWriter(stream);

   // Populate audio clip floats into buffer stream
   foreach (var sample in floatArrayOfAudioClip)
   {
       writer.Write(sample);
   }

   byte[] bytes = stream.ToArray();

   return bytes;
}

From unity’s docs at Unity - Scripting API: AudioClip.GetData

“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.”

Thanks, Tzuri. How would I implement this with user-generated microphone recordings, as no files are being loaded into memory?

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.

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.

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.

And if you play the clip on the client side after Microphone.End(), does it play as expected?

I found this:

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 :confused:

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.

1 Like