App.xaml.cs was 461 lines / 21KB and conflated four concerns: process- level lifecycle (mutex / message pump filter / shutdown), engine bootstrap (NDI runtime / IsoController / view model construction), crash handling (three exception channels + log directory + dialog), and the background update-checker kickoff. Splits via partial-class into themed sibling files: * App.xaml.cs (was 461L → now 219L) — class skeleton, fields, internal property accessors, Win32 P/Invoke surface, OnStartup as a wiring pipeline that calls the bootstrap steps in order, OnExit, CLI parser. * App.Bootstrap.cs (250L, new) — linear startup steps: TryAcquireSingleInstance, TryBootstrapNdiInterop, BootstrapEngine, ConstructAndShowMainWindow, BootstrapControlSurfaceServices, BootstrapTrayIcon, TryShowOnboarding, TryAutoLaunchTeams. Each returns a signal (bool / window ref) when OnStartup needs it to decide whether to continue. * App.CrashHandlers.cs (93L, new) — OnAppDomainUnhandled, OnDispatcherUnhandled, OnUnobservedTaskException, TryLogFatal, TryShowCrashDialog, LogDirectory. * App.UpdateCheckBootstrap.cs (42L, new) — StartBackgroundUpdateCheck (24h-throttled, fire-and-forget). OnStartup's body is now a 30-ish-line procedure that names each step, which is what the original was trying to be. Comments inline the "happened before, kept here for reason X" notes (theme.Apply before window show; CLI args parsed before InitializeAsync). Behavior is unchanged — Shutdown codes, error paths, and the side-effect order are all preserved. Build clean (0 warnings, 0 errors); 56 + 104 tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| docs | ||
| installer | ||
| src | ||
| .editorconfig | ||
| .gitignore | ||
| build-and-test.ps1 | ||
| CHANGELOG.md | ||
| commit-and-push.ps1 | ||
| coverlet.runsettings | ||
| DESIGN.md | ||
| Directory.Build.props | ||
| NEXT_STEPS.md | ||
| PRODUCT.md | ||
| README.md | ||
| TeamsISO.Linux.slnf | ||
| TeamsISO.sln | ||
| TeamsISO.Windows.slnf | ||
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 into a switcher (vMix, OBS, Ross, hardware capture).
What it does
- Discovers participants as Teams broadcasts each one over NDI, surfacing the operator-friendly display name (handles current "MS Teams - Name" format and the legacy "(Teams) Name" format).
- 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
output-name template (
TEAMSISO_{name},{guid},{machine},{timestamp}tokens). - Records each ISO to disk simultaneously — raw BGRA + sidecar manifest.json
- ffmpeg convert.cmd — so post-production gets a clean per-guest archive.
- Embeds Teams orchestration: launch and stop Teams from the rail, hide Teams' UI windows during a show, drive in-call controls (mute, camera, share, leave, raise hand) via UIAutomation.
- Operator presets save the current per-participant ISO assignment and custom output names, applicable on next launch automatically.
- Live preview thumbnails per participant in the participants table, plus pop-out floating preview windows (right-click → Open preview…) for multi-monitor monitoring.
- External control surface — REST + WebSocket on
127.0.0.1:9755and OSC on UDP127.0.0.1:9000for Bitfocus Companion / Stream Deck / TouchOSC integration. Self-contained HTML control panel at/uifor phone-as-controller. - Crash diagnostics wired to a rolling daily Serilog file sink under
%LOCALAPPDATA%\TeamsISO\Logs\. - Update check against
forge.wilddragon.net's release API — manual or silent on launch (throttled to 24h). - Diagnostic bundle export zips logs + config + presets for bug reports.
Status
Pre-1.0. The May 2026 batch is feature-complete; v1.0 cut is gated on
code-signing the MSI and a smoke pass against a real Teams meeting.
See CHANGELOG.md for the [Unreleased] entry.
The May 2026 ground-up redesign — the v2 "Studio Terminal" shell — has
landed on the WPF host (src/TeamsISO.App/). A WinUI 3 replatform was
explored in early May 2026 and abandoned (activation blockers + redundant
work given the redesign is purely XAML / view-layer); the brief lives at
docs/shapes/2026-05-13-teamsiso-v2-studio-terminal.md, and the
abandoned migration plan + bootstrap probe are archived under
docs/archive/.
Build
Requires .NET 8 SDK on Windows. WPF is the only host:
src/TeamsISO.App— WPF,net8.0-windows, the shipping build
Build from the solution filter:
dotnet restore TeamsISO.Windows.slnf
dotnet build TeamsISO.Windows.slnf -c Release
dotnet test TeamsISO.Windows.slnf --filter "Category!=ndi&requires!=ndi"
The shipped helper scripts in the repo root automate this:
pwsh -File .\build-and-test.ps1
pwsh -File .\commit-and-push.ps1
Documentation
- Control surface API — REST + WebSocket + OSC reference with curl recipes and a Companion config example.
- Releasing — tag-push workflow, MSI signing path.
- Architecture spec — design overview.
- Embedded Teams orchestration spec — Phase E roadmap.
- Redesign brief + design system — token-level spec for the v2 "Studio Terminal" redesign.
- v2 shape brief — approved aesthetic + IA for the May 2026 WPF rebuild.
Keyboard shortcuts
| Key | Action |
|---|---|
F1 |
Open help / cheat sheet |
Ctrl + K |
Open the command palette (also Ctrl + P) |
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) |
1–9 / NumPad 1–9 |
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 |
License
Proprietary, © Wild Dragon LLC 2026.