0
\$\begingroup\$

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.

=======

EDIT: It looks like the GetData method returns an array full of NULL characters if the AudioClip it is used on is compressed. Microphone recordings in unity are .ogg (compressed audio) format apparently.

Is there a way to get the float values out of an AudioClip without using I/O operations or the GetData method?

=======

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;
 }
\$\endgroup\$
2
  • \$\begingroup\$ "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." -- AudioClip.GetData \$\endgroup\$
    – Mangata
    Commented Jan 5, 2023 at 6:17
  • \$\begingroup\$ Yes, this was information was added in the edit. The issue here is that the AudioClip is not loaded into memory as it does not come from a file. The AudioClip is a user generated recording, so there is no LoadType or compression parameters (that I am aware of). \$\endgroup\$
    – cadburia
    Commented Jan 5, 2023 at 12:41

1 Answer 1

1
\$\begingroup\$

After testing, your code for obtaining byte arrays is valid, and the problem may be in the place of uploading data.

This byte array may not be all 0. Due to the sample format, there is a high probability that a section of the array (for example, the first 500) will have a value of 0. Maybe you use a debugging tool to view it and mistakenly think it is all 0.

You can use the following code to detect the proportion of 0 in the array:

byte[] bytes = stream.ToArray();
CountZero(bytes);
...

private static void CountZero<T>(T[] array) where T : IEquatable<T>
{
    var count = 0;
    foreach (var item in array)
    {
        if (item.Equals(default(T)))
        {
            count++;
        }
    }
    Debug.Log(1f * count / array.Length);
}

From my testing, this scale value decreases over time as expected, starting from the recording.

UnityWebRequest.Result.ProtocolError shows that it is an error as defined by the connection protocol. For the HTTP protocol, response codes 4xx and 5xx mean errors.

You can find the specific error code with UnityWebRequest.responseCode.

And find the meaning of the code on wiki/List_of_HTTP_status_codes.

\$\endgroup\$
1
  • \$\begingroup\$ You are right that the scale value decreases over time but the value is still >.9 for 10s and below, which is quite a lot of 0. Also, I can see what is being sent by UWR because I am just printing out the file that are being sent with the request on the server side, and it is mainly 0. The server doesn't recognise what is being sent as a legitimate file, and responds with an error accordingly. \$\endgroup\$
    – cadburia
    Commented Jan 5, 2023 at 17:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .