gpt4 book ai didi

c# - Unity 通过网络发送和接收麦克风音频

转载 作者:行者123 更新时间:2023-12-05 06:26:43 30 4
gpt4 key购买 nike

我有两个应用程序,一个用于服务器,另一个用于客户端。在服务器中,我试图从麦克风接收音频并将其通过 Tcp/Ip 流式传输到客户端。但是在客户端应用程序中,当我转换从服务器接收到的字节 [] 时,它会给我这个错误“NullReferenceException:对象引用未设置为对象的实例

服务器

using UnityEngine;
using System.Collections;
using System.IO;
using UnityEngine.UI;
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Generic;

public class AudioServer1 : MonoBehaviour
{

public bool enableLog = false;

private TcpListener listner;
private const int port = 8010;
private bool stop = false;

private List<TcpClient> clients = new List<TcpClient>();

//This must be the-same with SEND_COUNT on the client
const int SEND_RECEIVE_COUNT = 15;


int lastSample = 0;
public int FREQUENCY = 44100;
AudioClip mic;
int lastPos, pos;
byte[] AudioBytes = null;
private void Start()
{
Application.runInBackground = true;

mic = Microphone.Start(null, true, 10, FREQUENCY);

AudioSource audio = GetComponent<AudioSource>();
audio.clip = AudioClip.Create("test", 10 * FREQUENCY, mic.channels, FREQUENCY, false);
audio.loop = true;

//Start Mic coroutine
StartCoroutine(initAndWaitForMicTexture());
}


//Converts the data size to byte array and put result to the fullBytes array
void byteLengthToFrameByteArray(int byteLength, byte[] fullBytes)
{
//Clear old data
Array.Clear(fullBytes, 0, fullBytes.Length);
//Convert int to bytes
byte[] bytesToSendCount = BitConverter.GetBytes(byteLength);
//Copy result to fullBytes
bytesToSendCount.CopyTo(fullBytes, 0);
}

//Converts the byte array to the data size and returns the result
int frameByteArrayToByteLength(byte[] frameBytesLength)
{
int byteLength = BitConverter.ToInt32(frameBytesLength, 0);
return byteLength;
}

IEnumerator initAndWaitForMicTexture()
{


// Connect to the server
listner = new TcpListener(IPAddress.Any, port);

listner.Start();

while (101 < 100)
{
yield return null;
}

//Start sending coroutine
StartCoroutine(senderCOR());
}

WaitForEndOfFrame endOfFrame = new WaitForEndOfFrame();
IEnumerator senderCOR()
{

bool isConnected = false;
TcpClient client = null;
NetworkStream stream = null;

// Wait for client to connect in another Thread
Loom.RunAsync(() =>
{
while (!stop)
{
// Wait for client connection
client = listner.AcceptTcpClient();
// We are connected
clients.Add(client);

isConnected = true;
stream = client.GetStream();
}
});

//Wait until client has connected
while (!isConnected)
{
yield return null;
}

LOG("Connected!");

bool readyToGetFrame = true;

byte[] frameBytesLength = new byte[SEND_RECEIVE_COUNT];

while (!stop)
{
//Wait for End of frame
yield return endOfFrame;
byte[] pngBytes = AudioBytes;
//Fill total byte length to send. Result is stored in frameBytesLength
byteLengthToFrameByteArray(pngBytes.Length, frameBytesLength);

//Set readyToGetFrame false
readyToGetFrame = false;

Loom.RunAsync(() =>
{
//Send total byte count first
stream.Write(frameBytesLength, 0, frameBytesLength.Length);
LOG("Sent Audio byte Length: " + frameBytesLength.Length);

//Send the Audio bytes
stream.Write(pngBytes, 0, pngBytes.Length);
LOG("Sending Audio byte array data : " + pngBytes.Length);

//Sent. Set readyToGetFrame true
readyToGetFrame = true;
});

//Wait until we are ready to get new frame(Until we are done sending data)
while (!readyToGetFrame)
{
LOG("Waiting To get new frame");
yield return null;
}
}
}


void LOG(string messsage)
{
if (enableLog)
Debug.Log(messsage);
}

private void Update()
{
if ((pos = Microphone.GetPosition(null)) > 0)
{
if (lastPos > pos) lastPos = 0;

if (pos - lastPos > 0)
{
// Allocate the space for the sample.
float[] sample = new float[(pos - lastPos) * mic.channels];

// Get the data from microphone.
mic.GetData(sample, 0);

AudioBytes = ToByteArray(sample);
}
}
}

// stop everything
private void OnApplicationQuit()
{


if (listner != null)
{
listner.Stop();
}

foreach (TcpClient c in clients)
c.Close();
}
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;
}
}

客户端

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System;

public class AudioClient1 : MonoBehaviour
{

public bool enableLog = false;

const int port = 8010;
public string IP = "192.168.10.2";
TcpClient client;



private bool stop = false;

//This must be the-same with SEND_COUNT on the server
const int SEND_RECEIVE_COUNT = 15;

// Use this for initialization
void Start()
{
Application.runInBackground = true;

//tex = new Texture2D(0, 0);
client = new TcpClient();

//Connect to server from another Thread
Loom.RunAsync(() =>
{
LOGWARNING("Connecting to server...");
// if on desktop
client.Connect(IPAddress.Loopback, port);

// if using the IPAD
//client.Connect(IPAddress.Parse(IP), port);
LOGWARNING("Connected!");

AudioReceiver();
});
}


void AudioReceiver()
{
//While loop in another Thread is fine so we don't block main Unity Thread
Loom.RunAsync(() =>
{
while (!stop)
{
//Read Audio Count
int AudioSize = readAudioByteSize(SEND_RECEIVE_COUNT);
LOGWARNING("Received Audio byte Length: " + AudioSize);

//Read Audio Bytes and Display it
readFrameByteArray(AudioSize);
}
});
}


//Converts the data size to byte array and put result to the fullBytes array
void byteLengthToFrameByteArray(int byteLength, byte[] fullBytes)
{
//Clear old data
Array.Clear(fullBytes, 0, fullBytes.Length);
//Convert int to bytes
byte[] bytesToSendCount = BitConverter.GetBytes(byteLength);
//Copy result to fullBytes
bytesToSendCount.CopyTo(fullBytes, 0);
}

//Converts the byte array to the data size and returns the result
int frameByteArrayToByteLength(byte[] frameBytesLength)
{
int byteLength = BitConverter.ToInt32(frameBytesLength, 0);
return byteLength;
}


/////////////////////////////////////////////////////Read Audio SIZE from Server///////////////////////////////////////////////////
private int readAudioByteSize(int size)
{
bool disconnected = false;

NetworkStream serverStream = client.GetStream();
byte[] AudioBytesCount = new byte[size];
var total = 0;
do
{
var read = serverStream.Read(AudioBytesCount, total, size - total);
//Debug.LogFormat("Client recieved {0} bytes", total);
if (read == 0)
{
disconnected = true;
break;
}
total += read;
} while (total != size);

int byteLength;

if (disconnected)
{
byteLength = -1;
}
else
{
byteLength = frameByteArrayToByteLength(AudioBytesCount);
}
return byteLength;
}

/////////////////////////////////////////////////////Read Audio Data Byte Array from Server///////////////////////////////////////////////////
private void readFrameByteArray(int size)
{
bool disconnected = false;

NetworkStream serverStream = client.GetStream();
byte[] AudioBytes = new byte[size];
var total = 0;
do
{
var read = serverStream.Read(AudioBytes, total, size - total);
//Debug.LogFormat("Client recieved {0} bytes", total);
if (read == 0)
{
disconnected = true;
break;
}
total += read;
} while (total != size);

bool readyToReadAgain = false;

//Play Audio
if (!disconnected)
{
//Play Audio on the main Thread
Loom.QueueOnMainThread(() =>
{
displayReceivedAudio(AudioBytes);
readyToReadAgain = true;
});
}

//Wait until old Audio is displayed
while (!readyToReadAgain)
{
System.Threading.Thread.Sleep(1);
}
}


void displayReceivedAudio(byte[] receivedAudioBytes)
{
Debug.Log(receivedAudioBytes.Length);
// Put the data in the audio source.
AudioSource audio = GetComponent<AudioSource>();
audio.clip.SetData(ToFloatArray(receivedAudioBytes), 0);

if (!audio.isPlaying) audio.Play();
}
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;
}

// Update is called once per frame
void Update()
{


}


void LOG(string messsage)
{
if (enableLog)
Debug.Log(messsage);
}

void LOGWARNING(string messsage)
{
if (enableLog)
Debug.LogWarning(messsage);
}

void OnApplicationQuit()
{
LOGWARNING("OnApplicationQuit");
stop = true;

if (client != null)
{
client.Close();
}
}
}

我得到的错误是在下面的代码中

    void displayReceivedAudio(byte[] receivedAudioBytes)
{
Debug.Log(receivedAudioBytes.Length);
// Put the data in the audio source.
AudioSource audio = GetComponent<AudioSource>();
audio.clip.SetData(ToFloatArray(receivedAudioBytes), 0);

if (!audio.isPlaying) audio.Play();
}

最佳答案

此代码应该进行更多优化,但首先您肯定会在这一行中遇到错误:

audio.clip.SetData(ToFloatArray(receivedAudioBytes), 0);

因为你的剪辑是空的,你应该使用 Create 检查这个链接: https://docs.unity3d.com/ScriptReference/AudioClip.Create.html

关于c# - Unity 通过网络发送和接收麦克风音频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55779470/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com