using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Options;
using DeviceAgent.Models;
namespace DeviceAgent.Services;
///
/// SignalR 信令客户端 - 连接到服务器接收质量控制指令
///
public class SignalingClientService : IDisposable
{
private readonly ILogger _logger;
private readonly AgentConfig _config;
private readonly DeviceInfoService _deviceInfoService;
private ScreenStreamService? _screenStreamService;
private HubConnection? _connection;
private bool _isConnected;
private CancellationTokenSource? _reconnectCts;
public SignalingClientService(
ILogger logger,
IOptions config,
DeviceInfoService deviceInfoService)
{
_logger = logger;
_config = config.Value;
_deviceInfoService = deviceInfoService;
}
///
/// 设置 ScreenStreamService 引用(避免循环依赖)
///
public void SetScreenStreamService(ScreenStreamService screenStreamService)
{
_screenStreamService = screenStreamService;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
if (!_config.ScreenStreamEnabled)
{
_logger.LogInformation("屏幕流已禁用,跳过信令连接");
return;
}
try
{
var hubUrl = $"{_config.ServerUrl}/hubs/stream-signaling";
_logger.LogInformation("连接到信令服务器: {HubUrl}", hubUrl);
_connection = new HubConnectionBuilder()
.WithUrl(hubUrl)
.WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10) })
.Build();
// 注册事件处理器
RegisterHandlers();
// 连接事件
_connection.Reconnecting += error =>
{
_logger.LogWarning("信令连接断开,正在重连...");
_isConnected = false;
return Task.CompletedTask;
};
_connection.Reconnected += async connectionId =>
{
_logger.LogInformation("信令连接已恢复: {ConnectionId}", connectionId);
_isConnected = true;
await RegisterDeviceAsync();
};
_connection.Closed += async error =>
{
_logger.LogWarning("信令连接关闭: {Error}", error?.Message);
_isConnected = false;
// 自动重连
await Task.Delay(5000, cancellationToken);
if (!cancellationToken.IsCancellationRequested)
{
await StartAsync(cancellationToken);
}
};
// 启动连接
await _connection.StartAsync(cancellationToken);
_isConnected = true;
_logger.LogInformation("信令连接已建立");
// 注册设备
await RegisterDeviceAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "启动信令客户端失败");
}
}
private void RegisterHandlers()
{
if (_connection == null) return;
// 服务器通知切换质量
_connection.On("SetQuality", async (quality) =>
{
_logger.LogInformation("收到质量切换指令: {Quality}", quality);
if (_screenStreamService != null)
{
var profile = quality.ToLower() == "high"
? StreamQualityProfile.High
: StreamQualityProfile.Low;
_screenStreamService.SetQuality(profile);
}
});
// 服务器通知开始推流
_connection.On("StartStreaming", async (quality) =>
{
_logger.LogInformation("收到开始推流指令: {Quality}", quality);
if (_screenStreamService != null)
{
var profile = quality.ToLower() == "high"
? StreamQualityProfile.High
: StreamQualityProfile.Low;
_screenStreamService.SetQuality(profile);
}
// 注意:ScreenStreamService 已经在运行,这里只是切换质量
});
// 服务器通知停止推流
_connection.On("StopStreaming", async () =>
{
_logger.LogInformation("收到停止推流指令");
// 切换到低质量,实际推流由客户端连接数控制
if (_screenStreamService != null)
{
_screenStreamService.SetQuality(StreamQualityProfile.Low);
}
});
// 批量设备质量控制
_connection.On, string>("DevicesNeedStream", async (deviceUuids, quality) =>
{
var myUuid = _deviceInfoService.GetDeviceInfo().Uuid;
if (deviceUuids.Contains(myUuid) && _screenStreamService != null)
{
_logger.LogInformation("设备在监控列表中,质量: {Quality}", quality);
var profile = quality.ToLower() == "high"
? StreamQualityProfile.High
: StreamQualityProfile.Low;
_screenStreamService.SetQuality(profile);
}
});
_connection.On>("DevicesStopStream", async (deviceUuids) =>
{
var myUuid = _deviceInfoService.GetDeviceInfo().Uuid;
if (deviceUuids.Contains(myUuid) && _screenStreamService != null)
{
_logger.LogInformation("设备停止监控");
_screenStreamService.SetQuality(StreamQualityProfile.Low);
}
});
_connection.On("DeviceQualityChange", async (deviceUuid, quality) =>
{
var myUuid = _deviceInfoService.GetDeviceInfo().Uuid;
if (deviceUuid == myUuid && _screenStreamService != null)
{
_logger.LogInformation("设备质量切换: {Quality}", quality);
var profile = quality.ToLower() == "high"
? StreamQualityProfile.High
: StreamQualityProfile.Low;
_screenStreamService.SetQuality(profile);
}
});
}
private async Task RegisterDeviceAsync()
{
if (_connection == null || !_isConnected) return;
try
{
var uuid = _deviceInfoService.GetDeviceInfo().Uuid;
await _connection.InvokeAsync("RegisterDevice", uuid);
_logger.LogInformation("设备已注册到信令服务器: {Uuid}", uuid);
}
catch (Exception ex)
{
_logger.LogError(ex, "注册设备失败");
}
}
public async Task StopAsync()
{
if (_connection != null)
{
try
{
var uuid = _deviceInfoService.GetDeviceInfo().Uuid;
await _connection.InvokeAsync("UnregisterDevice", uuid);
_logger.LogInformation("设备已从信令服务器注销");
}
catch { }
await _connection.StopAsync();
await _connection.DisposeAsync();
_connection = null;
}
_isConnected = false;
_logger.LogInformation("信令客户端已停止");
}
public void Dispose()
{
_reconnectCts?.Cancel();
_reconnectCts?.Dispose();
_connection?.DisposeAsync().AsTask().Wait();
}
}