Код: Выделить всё
while (!stoppingToken.IsCancellationRequested)
{
try
{
if (_udpClient == null)
{
// Explicit binding to match DDPHelper robustness
var localEP = new IPEndPoint(IPAddress.Any, ListenPort);
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
// CRITICAL: Increase receive buffer size for high-frequency UDP on macOS
// Default macOS buffer may be too small, causing packet delays/drops
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, 96); // 256KB
socket.Bind(localEP);
_udpClient = new UdpClient { Client = socket };
// Log actual buffer size (OS may override our request)
var actualBufferSize = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer)!;
Console.WriteLine($"UDP Service: Bound successfully. Receive buffer: {actualBufferSize} bytes");
_fpsWatch.Start();
}
// 2. Processing Loop - CRITICAL: Use synchronous receive to prevent macOS kernel batching
while (!stoppingToken.IsCancellationRequested && _udpClient != null)
{
try
{
// CRITICAL FIX: Synchronous Receive() instead of ReceiveAsync()
// macOS batches async UDP receives at kernel level, causing jerky delivery
if (_udpClient.Available > 0)
{
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
byte[] buffer = _udpClient.Receive(ref remoteEP);
if (buffer.Length == 96)
{
LastFrame = buffer;
_frameCount++;
// Log FPS every 60 frames to diagnose UDP receive rate
if (_frameCount % 60 == 0)
{
double fps = _frameCount / _fpsWatch.Elapsed.TotalSeconds;
Console.WriteLine($"UDP Receive FPS: {fps:F1} ({_frameCount} frames in {_fpsWatch.Elapsed.TotalSeconds:F1}s)");
}
// Send directly to WebSocket clients - no throttling
MusicDongleWebSocketHandler.BroadcastFrame(buffer);
}
}
else
{
// No data available, yield to prevent busy-waiting
await Task.Delay(1, stoppingToken);
}
}
catch (OperationCanceledException)
{
break; // Stopping
}
catch (SocketException sex)
{
Console.WriteLine($"UDP Socket Error: {sex.Message}. Reinitializing...");
_udpClient?.Dispose();
_udpClient = null;
break; // Break info loop to re-bind
}
catch (Exception ex)
{
Console.WriteLine($"UDP Packet Error: {ex.Message}");
await Task.Delay(100, stoppingToken);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"UDP Bind/Outer Error: {ex.Message}. Retrying in 5s...");
_udpClient?.Dispose();
_udpClient = null;
// Wait before retrying bind
await Task.Delay(5000, stoppingToken);
}
}
Console.WriteLine("UDP Service: Stopping...");
_udpClient?.Dispose();
}
Если я запускаю эту функцию в MacOS, кажется, что она каким-то образом буферизуется. Мои пакеты всегда содержат 96 байт данных и приходят со скоростью 30 кадров в секунду, и мне не удалось добиться того, чтобы они не пропускали кадры. Я попробовал множество вещей, в том числе сделал его синхронным вместо асинхронного, а также протестировал его с полной переработкой, чтобы он работал в старом стиле, где каждый полученный кадр устанавливает новое событие.
Мне нужен кто-то, кто подскажет мне, как заставить буфер выдавать мне мои данные по команде.
Подробнее здесь: https://stackoverflow.com/questions/798 ... g-on-macos
Мобильная версия