mirror of
https://github.com/Dadechin/Unity-WebSocket.git
synced 2025-07-03 03:44:34 +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();
|
||
}
|
||
}
|