How to stream live audio via microphone in Unity3D?
Asked Answered
C

1

5

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.

Caliber answered 1/7, 2015 at 21:8 Comment(0)
C
3

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;
}
Caliber answered 9/7, 2015 at 16:40 Comment(3)
Unforuntately, this no longer works in the current version of Unity. Do you happen to have a Unity 5 solution?Blanding
I no longer have access to this project anymore. It was during an internship I had in 2015, otherwise I would've updated it.Caliber
@DanVioletSagmiller is there any new update available?Accursed

© 2022 - 2024 — McMap. All rights reserved.