namespace TeamsISO.App.Services; // /topology/* route handlers — read + apply / restore the machine NDI // access-manager config so the operator can flip transcoder topology // without leaving the web UI. // // GET /topology → GetTopology // POST /topology/apply → ApplyTopologyAsync // POST /topology/restore → RestoreTopologyAsync public sealed partial class ControlSurfaceServer { /// /// Report the current NDI machine topology. "mode" is "hidden" when /// local senders are confined to the private group (raw Teams sources /// invisible to the rest of the LAN), "public" otherwise. Reads the /// machine NDI config file directly — no caching, so the result /// reflects whatever state the file is in right now (including /// manual edits). /// private object GetTopology() { try { var (mode, sends, recvs) = NdiAccessManagerConfig.ReadCurrent(); return new { mode, senders = sends, receivers = recvs, configPath = NdiAccessManagerConfig.ConfigPath, }; } catch (Exception ex) { return new { ok = false, error = ex.Message }; } } /// /// Apply the transcoder topology: machine senders → teamsiso-input, /// receivers → public + teamsiso-input; engine groups updated to /// match (discover from teamsiso-input, broadcast on public). Operator /// MUST restart Teams afterward for it to read the new NDI config. /// private async Task ApplyTopologyAsync() { var result = NdiAccessManagerConfig.ApplyTranscoderTopology(); if (!result.Success) { return new { ok = false, error = result.ErrorMessage, configPath = result.ConfigPath }; } // Mirror what the WPF settings VM does so the engine groups + // machine config stay in lockstep. var ourGroups = new TeamsISO.Engine.Domain.NdiGroupSettings( DiscoveryGroups: NdiAccessManagerConfig.TranscoderInputGroup, OutputGroups: "public"); await _controller.SetGroupSettingsAsync(ourGroups, CancellationToken.None); return new { ok = true, mode = "hidden", backupPath = result.BackupPath, note = "Restart Microsoft Teams for the new NDI config to take effect there.", }; } /// /// Restore the machine NDI defaults: senders + receivers both on /// public. Engine groups go back to null/defaults too. Operator /// must restart Teams for it to broadcast on public again. /// private async Task RestoreTopologyAsync() { var result = NdiAccessManagerConfig.RestoreDefaults(); if (!result.Success) { return new { ok = false, error = result.ErrorMessage, configPath = result.ConfigPath }; } var ourGroups = new TeamsISO.Engine.Domain.NdiGroupSettings( DiscoveryGroups: null, OutputGroups: null); await _controller.SetGroupSettingsAsync(ourGroups, CancellationToken.None); return new { ok = true, mode = "public", backupPath = result.BackupPath, note = "Restart Microsoft Teams for the new NDI config to take effect there.", }; } }