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