Per-Participant NDI ISO Controller for Microsoft Teams. Receives Teams NDI streams, normalizes framerate/resolution, and re-emits clean ISO outputs for live production switchers (vMix, OBS, Ross). Wild Dragon LLC.
Find a file
ZGaetano 97a40f3ac2
All checks were successful
CI / build-and-test (push) Successful in 27s
fix(engine): don't leave a disposed finder behind on rebuild failure
RebuildFinder disposed the live finder *before* creating the replacement.
If CreateFinder threw (the documented failure mode the catch handles), the
service was left holding a disposed _finder, and every subsequent PollOnce
called GetCurrentSources on a dead handle — so the self-heal path could
permanently brick discovery, the exact outcome it exists to prevent. The
log even claimed "continuing with existing finder" while the finder was
gone.

Now we build the replacement into a local first and only dispose the old
finder once the new one is in hand. On failure the original finder stays
live and the seen-set is left intact (no spurious re-Add storm). Made the
method internal + bool-returning so the failure path is unit-testable.
2026-06-13 00:22:55 -04:00
.forgejo/workflows fix(installer): embed CAB in MSI + lower CI coverage threshold 2026-06-06 16:28:11 -04:00
docs rebrand: rename all TeamsISO source paths to Dragon-ISO 2026-05-31 11:18:27 -04:00
installer fix(installer): embed CAB in MSI + lower CI coverage threshold 2026-06-06 16:28:11 -04:00
src fix(engine): don't leave a disposed finder behind on rebuild failure 2026-06-13 00:22:55 -04:00
.editorconfig chore: scaffold repo conventions and global build props 2026-05-07 15:07:53 +00:00
.gitignore rebrand: rename all TeamsISO source paths to Dragon-ISO 2026-05-31 11:18:27 -04:00
build-and-test.ps1 rebrand: rename all TeamsISO source paths to Dragon-ISO 2026-05-31 11:18:27 -04:00
CHANGELOG.md rebrand: rename all TeamsISO source paths to Dragon-ISO 2026-05-31 11:18:27 -04:00
coverlet.runsettings ci: enforce 80% line coverage gate on TeamsISO.Engine 2026-05-07 15:16:11 +00:00
Directory.Build.props release: cut v1.0.0 — trim internal docs, polish README/CHANGELOG/MSI metadata 2026-05-17 19:03:33 -04:00
Dragon-ISO.Linux.slnf rebrand: rename all TeamsISO source paths to Dragon-ISO 2026-05-31 11:18:27 -04:00
Dragon-ISO.sln rebrand: rename all TeamsISO source paths to Dragon-ISO 2026-05-31 11:18:27 -04:00
Dragon-ISO.Windows.slnf rebrand: rename all TeamsISO source paths to Dragon-ISO 2026-05-31 11:18:27 -04:00
README.md release: cut v1.0.0 — trim internal docs, polish README/CHANGELOG/MSI metadata 2026-05-17 19:03:33 -04:00

TeamsISO

Per-participant NDI ISO controller for Microsoft Teams.

TeamsISO sits between Microsoft Teams' raw NDI broadcast output and a live-production environment. It receives each participant's NDI stream, normalizes framerate / resolution / aspect / audio per a configured target, and re-emits clean, individually-addressable NDI sources for ingestion by a switcher — vMix, OBS, Ross, hardware capture.

Status: v1.0.0 — first general release. Windows only. Requires Microsoft Teams (with NDI broadcast enabled) and the NDI 6 runtime.


What it does

  • Discovers participants as Teams broadcasts each one over NDI. Cleans the Teams-prefixed source name down to a readable display name.
  • Normalizes feeds to a consistent framerate, resolution, aspect mode, and audio routing — so the downstream switcher gets predictable inputs regardless of what each participant's webcam is doing.
  • Routes per-participant as separate NDI sources with a configurable per-row output name. Default is the speaker's display name; override inline in the participants table.
  • Records each ISO to disk simultaneously — raw BGRA + manifest.json
    • FFmpeg convert.cmd — so post-production gets a clean per-guest archive.
  • Embeds Teams orchestration: launch / stop Teams, hide its UI windows during a show, drive in-call controls (mute, camera, share, leave, raise hand) without leaving the operator console.
  • Operator presets save the current per-participant ISO assignment and custom output names, applicable on next launch automatically.
  • Live preview thumbnails in the participants table, plus pop-out floating preview windows for multi-monitor monitoring.
  • External control surface — REST + WebSocket on 127.0.0.1:9755 and OSC on UDP 127.0.0.1:9000 for Bitfocus Companion / Stream Deck / TouchOSC. Self-contained HTML panel at /ui for phone-as-controller.
  • Theme-aware — dark and light palettes, system-following or pinned. The Wild Dragon mark and watermark flip to match.

Install

Grab the latest MSI from the Releases page, double-click, and accept the install prompts. Per-machine install under C:\Program Files\Wild Dragon\TeamsISO.

Prerequisites:

  • Windows 10 / 11, 64-bit
  • .NET 8 Desktop Runtime
  • NDI 6 Runtime (the installer warns if missing but does not block — operators can stage the app before NDI is rolled out)
  • Microsoft Teams (NDI broadcast enabled in admin policy)

Configure

First-run defaults work for most setups. If your downstream switcher needs a particular framerate / resolution / NDI group routing, open the gear icon in the header to access the settings drawer:

  • Output — framerate, resolution, aspect mode, audio routing
  • Network — NDI discovery and output group names
  • App — recording paths, startup behavior, theme

Per-participant overrides — click the CFG column gear on any row to override framerate / resolution / aspect / audio for just that participant.

Keyboard shortcuts

Key Action
F1 Open help / cheat sheet
Ctrl + K (or Ctrl + P) Open the command palette
Ctrl + T Toggle theme (dark ↔ light)
Ctrl + M Drop a timestamped marker into every active recording
Ctrl + Shift + S Stop every running ISO (emergency)
Ctrl + R Refresh NDI discovery (rebuild finder)
19 / NumPad 19 Toggle the Nth visible participant's ISO

File locations

Path Contents
%APPDATA%\TeamsISO\config.json Engine settings (framerate, NDI groups, etc.)
%LOCALAPPDATA%\TeamsISO\presets.json Saved operator presets + auto-apply preference
%LOCALAPPDATA%\TeamsISO\logs\ Rolling daily diagnostic logs
%LOCALAPPDATA%\TeamsISO\Notes\ Per-day show-notes markdown files
%USERPROFILE%\Videos\TeamsISO\<date>\ Default recording output
%APPDATA%\NDI\ndi-config.v1.json NDI Access Manager group routing

Documentation

  • Control surface API — REST, WebSocket, and OSC reference with curl recipes and a Companion config example.
  • Real-time recording — recorder format, manifest schema, and the FFmpeg conversion path.
  • Releasing — tag-push workflow and MSI signing.

Build from source

Requires the .NET 8 SDK on Windows. WPF is the only host.

dotnet restore TeamsISO.Windows.slnf
dotnet build   TeamsISO.Windows.slnf -c Release
dotnet test    TeamsISO.Windows.slnf --filter "Category!=ndi&requires!=ndi"

Or use the included helper:

pwsh -File .\build-and-test.ps1

To produce a fresh MSI:

dotnet publish src\TeamsISO.App\TeamsISO.App.csproj `
    -c Release -r win-x64 --self-contained false `
    -o publish\TeamsISO
dotnet build installer\TeamsISO.Installer.wixproj -c Release
# Output: installer\bin\x64\Release\TeamsISO-Setup-<version>.msi

License

Proprietary, © Wild Dragon LLC 2026. All rights reserved.