private CameraServer() { m_defaultUsbDevice = 0; m_lockObject = new object(); m_sources = new Dictionary <string, VideoSource>(); m_sinks = new Dictionary <string, VideoSink>(); m_tables = new Dictionary <int, ITable>(); m_publishTable = NetworkTable.GetTable(PublishName); m_nextPort = BasePort; m_addresses = new List <string>(); m_videoListener = new VideoListener((vidEvent) => { switch (vidEvent.Kind) { case EventKind.SourceCreated: { // Create subtable for the camera ITable table = m_publishTable.GetSubTable(vidEvent.Name); lock (m_lockObject) { m_tables.Add(vidEvent.SourceHandle, table); } table.PutString("source", MakeSourceValue(vidEvent.SourceHandle)); table.PutString("description", NativeMethods.GetSourceDescription(vidEvent.SourceHandle)); table.PutBoolean("connected", NativeMethods.IsSourceConnected(vidEvent.SourceHandle)); table.PutStringArray("streams", GetSourceStreamValues(vidEvent.SourceHandle)); try { VideoMode mode = NativeMethods.GetSourceVideoMode(vidEvent.SourceHandle); table.SetDefaultString("mode", VideoModeToString(mode)); table.PutStringArray("modes", GetSourceModeValues(vidEvent.SourceHandle)); } catch (VideoException) { // Do nothing } break; } case EventKind.SourceDestroyed: { ITable table = GetSourceTable(vidEvent.SourceHandle); if (table != null) { table.PutString("source", ""); table.PutStringArray("streams", new string[0]); table.PutStringArray("modes", new string[0]); } break; } case EventKind.SourceConnected: { ITable table = GetSourceTable(vidEvent.SourceHandle); if (table != null) { // update the description too (as it may have changed) table.PutString("description", NativeMethods.GetSourceDescription(vidEvent.SourceHandle)); table.PutBoolean("connected", true); } break; } case EventKind.SourceDisconnected: { ITable table = GetSourceTable(vidEvent.SourceHandle); table?.PutBoolean("connected", false); break; } case EventKind.SourceVideoModesUpdated: { ITable table = GetSourceTable(vidEvent.SourceHandle); if (table != null) { table.PutStringArray("modes", GetSourceModeValues(vidEvent.SourceHandle)); } break; } case EventKind.SourceVideoModeChanged: { ITable table = GetSourceTable(vidEvent.SourceHandle); if (table != null) { table.PutString("mode", VideoModeToString(vidEvent.Mode)); } break; } case EventKind.SourcePropertyCreated: { ITable table = GetSourceTable(vidEvent.SourceHandle); if (table != null) { PutSourcePropertyValue(table, vidEvent, true); } break; } case EventKind.SourcePropertyValueUpdated: { ITable table = GetSourceTable(vidEvent.SourceHandle); if (table != null) { PutSourcePropertyValue(table, vidEvent, false); } break; } case EventKind.SourcePropertyChoicesUpdated: { ITable table = GetSourceTable(vidEvent.SourceHandle); if (table != null) { List <string> choices = NativeMethods.GetEnumPropertyChoices(vidEvent.PropertyHandle); table.PutStringArray($"PropertyInfo/{vidEvent.Name}/choices", choices); } break; } case EventKind.SinkSourceChanged: case EventKind.SinkCreated: case EventKind.SinkDestroyed: { UpdateStreamValues(); break; } case EventKind.NetworkInterfacesChanged: { m_addresses = NativeMethods.GetNetworkInterfaces(); break; } default: break; } }, (EventKind)0x4fff, true); m_tableListener = NtCore.AddEntryListener($"{PublishName}/", (uid, key, value, flags) => { string relativeKey = key.Substring(PublishName.Length + 1); int subKeyIndex = relativeKey.IndexOf('/'); if (subKeyIndex == -1) { return; } string sourceName = relativeKey.Substring(0, subKeyIndex); VideoSource source; if (!m_sources.TryGetValue(sourceName, out source)) { return; } relativeKey = relativeKey.Substring(subKeyIndex + 1); string propName; if (relativeKey == "mode") { // reset to current mode NtCore.SetEntryString(key, VideoModeToString(source.GetVideoMode())); return; } else if (relativeKey.StartsWith("Property/")) { propName = relativeKey.Substring(9); } else if (relativeKey.StartsWith("RawProperty/")) { propName = relativeKey.Substring(12); } else { return; } VideoProperty prop = source.GetProperty(propName); switch (prop.Kind) { case PropertyKind.None: return; case PropertyKind.Boolean: NtCore.SetEntryBoolean(key, prop.Get() != 0); break; case PropertyKind.Integer: case PropertyKind.Enum: NtCore.SetEntryDouble(key, prop.Get()); break; case PropertyKind.String: NtCore.SetEntryString(key, prop.GetString()); break; default: return; } }, NotifyFlags.NotifyImmediate | NotifyFlags.NotifyUpdate); }