namespace SHH.CameraSdk;
///
/// 增强型设备元数据中心 (V3.3.1 修复版)
/// 核心职责:
/// 1. 封装设备的硬件参数、通道能力、功能集,提供能力自发现
/// 2. 支持元数据同步与差异对比,指导上层模块执行差异化处理
/// 3. 存储运维指标与 SDK 原生句柄,支撑故障诊断与性能调优
/// 设计特性:只读优先,通过版本号标记同步状态,避免并发修改冲突
///
public class DeviceMetadata
{
#region --- 1. 设备级身份信息 (Identity) ---
/// 设备型号名称(如 DS-2CD3T47G2-LIU)
public string ModelName { get; init; } = "Unknown";
/// 设备唯一序列号(全局唯一,用于设备溯源)
public string SerialNumber { get; init; } = string.Empty;
/// 固件/系统版本号(用于判断 SDK 兼容性)
public string FirmwareVersion { get; init; } = string.Empty;
/// 所属厂商/品牌(决定驱动适配逻辑)
public DeviceBrand Brand { get; init; } = DeviceBrand.Unknown;
/// 元数据版本号(本地刷新计数,每次同步自增)
public long Version { get; private set; }
/// 最后同步时间(标记元数据的最新有效时刻)
public DateTime LastSyncedAt { get; private set; }
#endregion
#region --- 2. 级联能力模型 (Cascaded Capabilities) ---
private readonly ReadOnlyCollection _channels;
/// 通道元数据集合(只读,防止外部篡改)
public ReadOnlyCollection Channels
{
get => _channels;
init => _channels = value ?? new ReadOnlyCollection(new List());
}
/// 设备总通道数量(IPC 通常为 1,NVR 为接入路数)
public int ChannelCount => Channels.Count;
/// 索引器:通过通道号快速获取对应通道的能力描述
/// 物理通道号
/// 通道元数据 / 不存在则返回 null
public ChannelMetadata? this[int channelIndex] =>
Channels.FirstOrDefault(c => c.ChannelIndex == channelIndex);
#endregion
#region --- 3. 运维指标与非托管句柄 ---
/// 设备实时健康度字典(如 CPU 使用率、温度、内存占用等)
public Dictionary HealthMetrics { get; init; } = new();
///
/// 厂商 SDK 原始句柄/结构体快照
/// 注意事项:
/// 1. 标记 [JsonIgnore] 防止序列化非托管指针导致程序崩溃
/// 2. 仅用于驱动层与 SDK 交互,上层业务禁止直接操作
///
[JsonIgnore]
public object? NativeHandle { get; init; }
/// 厂商扩展标签(如设备位置、安装时间、责任人等自定义信息)
public Dictionary Tags { get; init; } = new();
#endregion
#region --- 4. 构造与同步 (Constructor & Sync) ---
///
/// 默认构造函数(用于 BaseVideoSource 初始状态,无通道数据)
///
public DeviceMetadata() : this(Enumerable.Empty()) { }
///
/// 完整构造函数(初始化通道元数据集合)
///
/// 通道元数据列表
public DeviceMetadata(IEnumerable channels)
{
// 转换为只读集合,确保通道数据不可变
_channels = new ReadOnlyCollection(channels?.ToList() ?? new List());
// 标记初始同步状态
MarkSynced();
}
///
/// 标记元数据同步完成
/// 作用:更新版本号与同步时间,用于差异对比的基准判断
///
public void MarkSynced()
{
Version++;
LastSyncedAt = DateTime.Now;
}
#endregion
#region --- 5. 业务逻辑辅助方法 (Business Helpers) ---
///
/// 校验动态流配置的合法性(基于设备能力)
///
/// 待校验的动态配置项
/// 校验失败时的详细原因
/// 合法返回 true,非法返回 false
public bool ValidateOptions(DynamicStreamOptions options, out string errorMessage)
{
errorMessage = string.Empty;
if (options == null) return true;
// 示例校验规则:云台控制权限校验
if (options.VendorExtensions?.ContainsKey("PtzAction") == true
&& !Channels.Any(c => c.SupportPtz))
{
errorMessage = "该设备物理硬件不支持云台控制功能";
return false;
}
// 可扩展其他校验规则:如分辨率合法性、码流类型支持性等
return true;
}
///
/// 元数据差异比对逻辑(用于 BaseVideoSource.RefreshMetadataAsync 方法)
///
/// 最新拉取的设备元数据
/// 元数据差异描述符
public MetadataDiff CompareWith(DeviceMetadata other)
{
// 入参防护:对比对象为空则返回无差异
if (other == null) return MetadataDiff.None;
return new MetadataDiff
{
// 1. 基础信息变更:任意通道名称变化则标记
NameChanged = this.Channels.Any(c =>
{
var targetChannel = other[c.ChannelIndex];
return targetChannel != null && targetChannel.Name != c.Name;
}),
// 2. 能力集变更:PTZ/音频/AI 功能支持状态变化则标记
CapabilityChanged = this.Channels.Any(c =>
{
var targetChannel = other[c.ChannelIndex];
if (targetChannel == null) return false;
return targetChannel.SupportPtz != c.SupportPtz
|| targetChannel.SupportAudioIn != c.SupportAudioIn
|| targetChannel.SupportAiAnalysis != c.SupportAiAnalysis;
}),
// 3. 致命变更:品牌不一致或通道数量变化(设备更换/替换场景)
IsMajorChange = this.Brand != other.Brand || this.ChannelCount != other.ChannelCount,
// 4. 分辨率配置变更:任意通道的分辨率档位数量变化则标记
ResolutionProfilesChanged = this.Channels.Any(c =>
{
var targetChannel = other[c.ChannelIndex];
return targetChannel != null
&& targetChannel.SupportedResolutions.Count != c.SupportedResolutions.Count;
})
};
}
#endregion
}