using TeamsISO.Engine.Domain; namespace TeamsISO.Engine.Discovery; /// /// Parses NDI source strings emitted by Microsoft Teams. /// /// Examples Teams emits: /// "MACHINE (Teams - Display Name)" /// "MACHINE (Teams)" — auto-mixed active speaker /// "MACHINE (Teams Audio)" — audio-only mix /// "MACHINE (Teams Screen Share)" — screen share /// public static class NdiSourceParser { public static NdiSource? Parse(string fullName) { if (string.IsNullOrWhiteSpace(fullName)) return null; // Find the last '(' so machine names can themselves contain parens. var openParen = fullName.LastIndexOf('('); if (openParen <= 0 || !fullName.EndsWith(')')) { // Try outer parens for cases like "MACHINE (Teams - Smith, Bob (PM))" // by walking from the first '(' that opens a "Teams" inner. var firstParen = fullName.IndexOf(" (Teams", StringComparison.Ordinal); if (firstParen <= 0) return null; openParen = firstParen + 1; if (!fullName.EndsWith(')')) return null; } else { // Re-anchor to the first " (Teams" if present, so display names containing // their own parens (e.g. "Smith, Bob (PM)") don't get truncated. var firstParen = fullName.IndexOf(" (Teams", StringComparison.Ordinal); if (firstParen > 0) openParen = firstParen + 1; } var machine = fullName[..openParen].TrimEnd(); if (machine.Length == 0) return null; var inner = fullName.Substring(openParen + 1, fullName.Length - openParen - 2).Trim(); if (!inner.StartsWith("Teams", StringComparison.Ordinal)) return null; if (inner == "Teams") return new NdiSource(fullName, machine, NdiSourceKind.ActiveSpeaker, DisplayName: null); if (inner == "Teams Audio") return new NdiSource(fullName, machine, NdiSourceKind.Audio, DisplayName: null); if (inner == "Teams Screen Share") return new NdiSource(fullName, machine, NdiSourceKind.ScreenShare, DisplayName: null); const string prefix = "Teams - "; if (inner.StartsWith(prefix, StringComparison.Ordinal)) { var display = inner[prefix.Length..].Trim(); if (display.Length == 0) return null; return new NdiSource(fullName, machine, NdiSourceKind.Participant, display); } return null; } }