using Newtonsoft.Json.Linq; using SHH.CameraSdk; // 引用包含 FrameController 和 FrameRequirement 的命名空间 using SHH.Contracts; namespace SHH.CameraService; public class SyncCameraHandler : ICommandHandler { private readonly CameraManager _cameraManager; public string ActionName => "SyncCamera"; public SyncCameraHandler(CameraManager cameraManager) { _cameraManager = cameraManager; } public async Task ExecuteAsync(JToken payload) { // 1. 解析配置 var dto = payload.ToObject(); if (dto == null) return; // 2. 添加设备到管理器 (这一步是必须的,不然没有 Device 就没有 Controller) var videoConfig = new VideoSourceConfig { Id = dto.Id, Name = dto.Name, IpAddress = dto.IpAddress, Port = dto.Port, Username = dto.Username, Password = dto.Password, ChannelIndex = dto.ChannelIndex, StreamType = dto.StreamType, Brand = (DeviceBrand)dto.Brand, RenderHandle = (IntPtr)dto.RenderHandle, MainboardIp = dto.MainboardIp, MainboardPort = dto.MainboardPort, // 必须给个默认值,防止空引用 VendorArguments = new Dictionary(), }; // 如果设备不存在才添加,如果已存在,后续逻辑会直接获取 if (_cameraManager.GetDevice(videoConfig.Id) == null) { _cameraManager.AddDevice(videoConfig); } // 3. 核心:直接获取设备实例 var device = _cameraManager.GetDevice(dto.Id); if (device == null) { Console.WriteLine($"[SyncError] 设备 {dto.Id} 创建失败,无法执行自动订阅。"); return; } // 4. 拿到你的“宝贝”控制器 (FrameController) var controller = device.Controller; if (controller == null) { Console.WriteLine($"[SyncError] 设备 {dto.Id} 不支持流控调度 (Controller is null)。"); return; } // 5. 暴力注册订阅需求 (Loop AutoSubscriptions) if (dto.AutoSubscriptions != null && dto.AutoSubscriptions.Count > 0) { foreach (var subItem in dto.AutoSubscriptions) { // 生成 AppId (照抄你给的逻辑) string finalAppId = string.IsNullOrWhiteSpace(subItem.AppId) ? $"SUB_{Guid.NewGuid().ToString("N").Substring(0, 8).ToUpper()}" : subItem.AppId; Console.WriteLine($"[自动化] 正在注册流控: {finalAppId}, 目标: {subItem.TargetFps} FPS"); // 构造 FrameRequirement 对象 (完全匹配你 FrameController 的入参) // 这里的属性赋值对应你代码里 req.Type, req.SavePath 等逻辑 var requirement = new FrameRequirement { AppId = finalAppId, TargetFps = subItem.TargetFps, // 8帧 或 1帧 Type = (SubscriptionType)subItem.Type, // 业务类型 (LocalWindow, NetworkTrans...) Memo = subItem.Memo ?? "Auto Sync", // 其它字段给默认空值,防止 Controller 内部逻辑报错 Handle = "", SavePath = "" }; // ★★★ 见证奇迹的时刻:直接调用 Register ★★★ controller.Register(requirement); } } //// 6. 启动设备 //// 你的积分算法会在 device 内部的推流循环中被 MakeDecision 调用 if (dto.ImmediateExecution) await device.StartAsync(); Console.WriteLine($"[SyncSuccess] 设备 {dto.Id} 同步完成,策略已下发。"); } }