How to stream live audio via microphone in Unity3D?

14,842

I decided to go back to the code posted here and try something different. The only differences I made was using FixedUpdate instead of Update and initiating the microphone inside FixedUpdate when a connection is made. There is a lot of stutter when using Update so I chose to work with FixedUpdate at a 0.5 second interval and it works.

int lastSample = 0;
void FixedUpdate()
{
    // If there is a connection
    if (Network.connections.Length > 0)
    {
        if (notRecording)
        {
            notRecording = false;
            sendingClip = Microphone.Start(null, true, 100, FREQUENCY);
            sending = true;
        }
        else if(sending)
        {
            int pos = Microphone.GetPosition(null);
            int diff = pos-lastSample;

            if (diff > 0)
            {
                float[] samples = new float[diff * sendingClip.channels];
                sendingClip.GetData (samples, lastSample);
                byte[] ba = ToByteArray (samples);
                networkView.RPC ("Send", RPCMode.Others, ba, sendingClip.channels);
                Debug.Log(Microphone.GetPosition(null).ToString());
            }
            lastSample = pos;
        }
    }
}

[RPC]
public void Send(byte[] ba, int chan) {
    float[] f = ToFloatArray(ba);
    audio.clip = AudioClip.Create("", f.Length, chan, FREQUENCY,true,false);
    audio.clip.SetData(f, 0);
    if (!audio.isPlaying) audio.Play();

}
// Used to convert the audio clip float array to bytes
public byte[] ToByteArray(float[] floatArray) {
    int len = floatArray.Length * 4;
    byte[] byteArray = new byte[len];
    int pos = 0;
    foreach (float f in floatArray) {
        byte[] data = System.BitConverter.GetBytes(f);
        System.Array.Copy(data, 0, byteArray, pos, 4);
        pos += 4;
    }
    return byteArray;
}
// Used to convert the byte array to float array for the audio clip
public float[] ToFloatArray(byte[] byteArray) {
    int len = byteArray.Length / 4;
    float[] floatArray = new float[len];
    for (int i = 0; i < byteArray.Length; i+=4) {
        floatArray[i/4] = System.BitConverter.ToSingle(byteArray, i);
    }
    return floatArray;
}
Share:
14,842
Zach
Author by

Zach

Updated on June 22, 2022

Comments

  • Zach
    Zach almost 2 years

    Here's part of the main code so far (the networking was done separately):

    void Update()
    {
        if (Network.connections.Length > 0) 
        {
            audioFloat = new float[audioInfo.clip.samples * audioInfo.clip.channels];
            audioInfo.clip.GetData (audioFloat, 0);
            networkView.RPC("PlayMicrophone", RPCMode.Others, ToByteArray(audioFloat), audioInfo.clip.channels);
        }
    }
    
    [RPC]
    void PlayMicrophone(byte[] ba, int c)
    {
        float[] flar = ToFloatArray (ba);
        audio.clip = AudioClip.Create ("test", flar.Length, c, 44100, true, false);
    
        audio.clip.SetData (flar, 0);
        audio.loop = true;
        while (!(Microphone.GetPosition("") > 0)) {}
        audio.Play();
    }
    
    void OnConnectedToServer()
    {
        audioInfo.clip = Microphone.Start(null, true, 100, 44100);
    }
    
    // When you are the server and the client connected to 
    void OnPlayerConnected(NetworkPlayer player)
    {
        audioInfo.clip = Microphone.Start(null, true, 100, 44100);
    }
    
    public byte[] ToByteArray(float[] floatArray) {
        int len = floatArray.Length * 4;
        byte[] byteArray = new byte[len];
        int pos = 0;
        foreach (float f in floatArray) {
            byte[] data = System.BitConverter.GetBytes(f);
            System.Array.Copy(data, 0, byteArray, pos, 4);
            pos += 4;
        }
        return byteArray;
    }
    
    public float[] ToFloatArray(byte[] byteArray) {
        int len = byteArray.Length / 4;
        float[] floatArray = new float[len];
        for (int i = 0; i < byteArray.Length; i+=4) {
            floatArray[i/4] = System.BitConverter.ToSingle(byteArray, i);
        }
        return floatArray;
    }
    

    I know it probably won't playback perfect, but I was expecting to hear even the slightest sound even for a second but it never happened. The data appears to be sent over the RPCs fine but the audio will not play.

    In the Update() function it will continually call the RPC to start playing from the microphone. This happens after the connection has been made as either a client or a server.

    Since you can't send any arrays besides byte arrays, I get the audio data as a float array then convert to a byte array to be sent over to the other person connected. There are no errors when the code is ran but the sound still never plays.

    The idea is to have fully live streaming 2-way audio gathered from the respective player's microphone. I feel like even though the buffer is only for 100 seconds it should still play sound up to that point.

    I will probably end up using a circular buffer for that when the time comes. The sound hasn't played at all yet.

    I tried using examples from Here and Here and was still unable to produce results.

  • Admin
    Admin over 7 years
    Unforuntately, this no longer works in the current version of Unity. Do you happen to have a Unity 5 solution?
  • Zach
    Zach over 7 years
    I no longer have access to this project anymore. It was during an internship I had in 2015, otherwise I would've updated it.
  • Muhammad Faizan Khan
    Muhammad Faizan Khan about 7 years
    @DanVioletSagmiller is there any new update available?