如何在Unity3D中通过麦克风流式传输实时音频
本文关键字:风流 麦克风 传输 音频 实时 麦克 Unity3D | 更新日期: 2023-09-27 18:00:39
以下是到目前为止的部分主代码(联网是单独完成的):
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以开始从麦克风播放。这种情况发生在作为客户端或服务器进行连接之后。
由于除了字节数组之外,您不能发送任何数组,因此我将音频数据作为浮点数组,然后转换为字节数组发送给连接的其他人。运行代码时没有错误,但声音仍然不会播放。
这个想法是从各个播放器的麦克风中收集完全实时的双向音频。我觉得即使缓冲区只有100秒,它也应该在这一点上播放声音。
到了这个时候,我可能会使用一个循环缓冲区。声音还没有播放。
我试着使用《这里》和《这里》中的例子,但仍然无法产生结果。
我决定回到这里发布的代码,尝试一些不同的东西。我所做的唯一区别是使用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;
}