Unity-WebSocket/Assets/OpusVoiceReceiverWithBuffer.cs
2025-06-28 11:28:54 +03:30

102 lines
3.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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