c# - 如何在 Unity3D 中通过麦克风流式传输实时音频?

原文 标签 c# unity3d network-programming audio-streaming microphone

到目前为止,这是主要代码的一部分(网络是单独完成的):

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;
}

我知道它可能不会完美播放,但我希望即使是一秒钟也能听到最轻微的声音,但它从未发生过。数据似乎是通过 RPC 发送的,但音频不会播放。

在 Update() 函数中,它将不断调用 RPC 以从麦克风开始播放。这发生在作为客户端或服务器建立连接之后。

由于除了字节数组之外您无法发送任何数组,因此我将音频数据作为浮点数组获取,然后转换为字节数组以发送给连接的其他人。运行代码时没有错误,但声音仍然没有播放。

这个想法是从各自播放器的麦克风中收集完全实时流式传输的 2 路音频。我觉得即使缓冲区只有 100 秒;到那时它仍然应该播放声音。

当时机成熟时,我可能最终会为此使用循环缓冲区。声音还没有播放。

我尝试使用来自 Here 的示例和 Here并且仍然无法产生结果。

非常感谢任何帮助,感谢您的阅读!

最佳答案

我决定回到发布的代码 here并尝试不同的东西。我所做的唯一区别是使用 FixedUpdate 而不是 Update 并在建立连接时在 FixedUpdate 内启动麦克风。使用 Update 时有很多卡顿,所以我选择以 0.5 秒的间隔使用 FixedUpdate 并且它有效。

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;
}

关于c# - 如何在 Unity3D 中通过麦克风流式传输实时音频?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31171714/

相关文章:

java - NIC吞吐量采样

c - 通过套接字发送任意长度的数组。字节序

c# - 如何在使用LINQ创建的xml中给出ISO-8859-1编码

c# - WPF/MVVM :'Could not load file or assembly' 和 'Type reference cannot find type'

c# - 以编程方式选择下一个列表框项

android - 以编程方式为 LinearLayout 设置重力

unity3d - 如何统一添加文本轮廓

c# - Unity3d 沿平面移动对象(仅限 X 和 Z 轴)

c# - C#-此代码在做什么,它叫什么?

c - 使用 NFQUEUE 发送排队的数据包?