mirror of
https://github.com/Dadechin/Unity-WebSocket.git
synced 2025-07-17 18:54:35 +00:00
102 lines
3.3 KiB
C#
102 lines
3.3 KiB
C#
|
using UnityEngine;
|
|||
|
using WebSocketSharp;
|
|||
|
using System.Threading;
|
|||
|
using Concentus.Structs;
|
|||
|
|
|||
|
public class OpusVoiceReceiverWithBuffer : MonoBehaviour
|
|||
|
{
|
|||
|
private WebSocket ws;
|
|||
|
private AudioSource audioSource;
|
|||
|
private OpusDecoder decoder;
|
|||
|
|
|||
|
private const int sampleRate = 16000;
|
|||
|
private const int channels = 1;
|
|||
|
|
|||
|
private const int clipLengthSeconds = 5; // طول کل AudioClip به ثانیه
|
|||
|
private AudioClip audioClip;
|
|||
|
|
|||
|
private float[] audioBuffer;
|
|||
|
private int bufferWritePos = 0;
|
|||
|
private int bufferReadPos = 0;
|
|||
|
private int bufferSize;
|
|||
|
|
|||
|
private object bufferLock = new object();
|
|||
|
|
|||
|
void Start()
|
|||
|
{
|
|||
|
audioSource = gameObject.AddComponent<AudioSource>();
|
|||
|
audioSource.loop = true;
|
|||
|
|
|||
|
decoder = new OpusDecoder(sampleRate, channels);
|
|||
|
|
|||
|
bufferSize = sampleRate * clipLengthSeconds; // اندازه بافر به تعداد نمونه ها
|
|||
|
audioBuffer = new float[bufferSize];
|
|||
|
|
|||
|
audioClip = AudioClip.Create("VoiceStream", bufferSize, channels, sampleRate, true, OnAudioRead, OnAudioSetPosition);
|
|||
|
audioSource.clip = audioClip;
|
|||
|
audioSource.Play();
|
|||
|
|
|||
|
ws = new WebSocket("ws://192.168.31.10:8765");
|
|||
|
ws.OnMessage += OnMessageReceived;
|
|||
|
ws.Connect();
|
|||
|
}
|
|||
|
|
|||
|
private void OnMessageReceived(object sender, MessageEventArgs e)
|
|||
|
{
|
|||
|
// دیکد کردن داده اوپوس
|
|||
|
short[] pcm = new short[960]; // 20ms frame at 16kHz
|
|||
|
int decodedSamples = decoder.Decode(e.RawData, 0, e.RawData.Length, pcm, 0, pcm.Length, false);
|
|||
|
|
|||
|
float[] floatSamples = new float[decodedSamples];
|
|||
|
for (int i = 0; i < decodedSamples; i++)
|
|||
|
floatSamples[i] = pcm[i] / (float)short.MaxValue;
|
|||
|
|
|||
|
// نوشتن در بافر حلقهای امن در برابر چند Thread
|
|||
|
lock (bufferLock)
|
|||
|
{
|
|||
|
for (int i = 0; i < decodedSamples; i++)
|
|||
|
{
|
|||
|
audioBuffer[bufferWritePos] = floatSamples[i];
|
|||
|
bufferWritePos = (bufferWritePos + 1) % bufferSize;
|
|||
|
|
|||
|
// در صورت پر شدن بافر، خواندن را جلو میبریم (دادههای قدیمی حذف میشوند)
|
|||
|
if (bufferWritePos == bufferReadPos)
|
|||
|
{
|
|||
|
bufferReadPos = (bufferReadPos + 1) % bufferSize;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// این تابع توسط AudioSource برای خواندن دادههای صوتی فراخوانی میشود
|
|||
|
void OnAudioRead(float[] data)
|
|||
|
{
|
|||
|
lock (bufferLock)
|
|||
|
{
|
|||
|
for (int i = 0; i < data.Length; i++)
|
|||
|
{
|
|||
|
if (bufferReadPos != bufferWritePos)
|
|||
|
{
|
|||
|
data[i] = audioBuffer[bufferReadPos];
|
|||
|
bufferReadPos = (bufferReadPos + 1) % bufferSize;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// اگر بافر خالی باشد، سکوت پخش میکنیم
|
|||
|
data[i] = 0f;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void OnAudioSetPosition(int newPosition)
|
|||
|
{
|
|||
|
// این تابع باید باشد ولی در اینجا کاری انجام نمیدهیم
|
|||
|
}
|
|||
|
|
|||
|
private void OnDestroy()
|
|||
|
{
|
|||
|
ws?.Close();
|
|||
|
}
|
|||
|
}
|