teamsiso/docs/superpowers/specs/2026-05-08-embedded-teams-orchestration.md
Zac Gaetano c08b90b0b2
All checks were successful
CI / build-and-test (push) Successful in 40s
feat(ui): Launch Teams rail button + spec for embedded-Teams roadmap
First step of Phase E.1 from the new spec at docs/superpowers/specs/2026-05-08-embedded-teams-orchestration.md: a third icon in the left rail launches the Microsoft Teams desktop client as a subprocess of TeamsISO so the operator doesn't have to leave the app to start a meeting.

Services/TeamsLauncher tries the ms-teams: URI first, falls back to %LOCALAPPDATA%\\Microsoft\\WindowsApps\\ms-teams.exe (new Teams), then the classic Update.exe handoff. On failure surfaces a friendly MessageBox with the install link.

The spec doc lays out the full three-phase roadmap (launcher -> window orchestration -> in-app meeting controls via Graph API or UIAutomation) and explicitly calls out what's out of scope (replacing Teams' media stack).

_NEXT.md updated to mark Phase D done and queue Phase E + remaining polish items (code-signing, Inter/JetBrains Mono font bundling, real Wild Dragon dragon-mark, drops counter, running-fps display).
2026-05-08 01:05:26 -04:00

4.7 KiB

Spec: Embedded Teams meeting orchestration

Status: Draft. Authored 2026-05-08.

Problem

Operators currently run two apps side by side: Microsoft Teams (which broadcasts NDI from its meetings) and TeamsISO (which consumes those NDI sources, normalizes them, and re-emits clean ISOs). Two issues fall out:

  1. Two interfaces, one workflow. Switching between Teams to drive the meeting and TeamsISO to drive ISO routing is friction during a live show.
  2. Teams' raw NDI bleeds into the production network. Even with TeamsISO running, Teams broadcasts its at-source-resolution / at-source-framerate feeds on the same Public NDI group that switchers and recorders subscribe to. Operators see "garbage" NDI sources alongside the clean TeamsISO outputs unless they manually configure NDI groups (which most don't).

The user's stated north star: let me host the meeting from inside TeamsISO. Run Teams in the background. Show me one interface; expose only the proper outputs.

Constraints

  • Microsoft Teams' NDI broadcast feature is desktop-only — the web client does not broadcast NDI. We cannot replace Teams with a WebView2 view of teams.microsoft.com.
  • We do not have a native Teams SDK. The Microsoft Graph API exposes some meeting control (create/join/end), but in-call operations (mute, share, react) are largely out of scope or behind enterprise tenant configuration.
  • Win32 window embedding (SetParent) of a foreign process's window is technically possible but produces a fragile UX — Teams will break out, render incorrectly, or fail to honor parent-window inputs.
  • NDI group routing is the standard primitive for hiding noisy producers. We shipped this in commit 909237f. It works.

Architecture

A three-phase rollout. Each phase is shippable on its own.

Phase E.1 — Teams launcher (launches Teams as a subprocess)

The minimum viable embed. TeamsISO grows a "Launch Teams" affordance on the rail. Clicking it:

  1. Reads the global NdiGroupSettings.DiscoveryGroups from EngineConfig. If empty, defaults to teamsiso-input.
  2. Opens NDI Access Manager (or programmatically writes its config) so Teams broadcasts on teamsiso-input rather than Public.
  3. Launches ms-teams: URI (or the MSTeams.exe directly for the new client) in the background.
  4. Marks Teams as "owned by TeamsISO" — the rail icon flips to "Stop Teams"; on click, sends WM_CLOSE to the Teams main window.
  5. Surfaces meeting health in the existing engine-status pill (e.g. "Teams running • 2 participants").

Implementation effort: a few hours. Pure WPF + ProcessStartInfo + a small NdiAccessManagerHelper that reads/writes Teams' config.

Phase E.2 — Window orchestration

Teams' main window is repositioned + minimized when launched, so the user's foreground experience is the TeamsISO window. Optional:

  • Pin Teams to a hidden virtual desktop with IVirtualDesktopManager.
  • Forward keyboard shortcuts (mute, camera, share) from TeamsISO into Teams via SendInput while Teams' window is hidden.

Implementation effort: a day. Mostly Win32 plumbing.

Phase E.3 — Meeting controls in TeamsISO's UI

A "Meeting" panel in the left rail that shows the active call's participant list (with their mute / video state) and exposes Join/Leave/Mute/Share controls. Two ways to plumb this:

  • Microsoft Graph API for the chrome. Auth as the user via OAuth (interactive device-code flow), poll /me/onlineMeetings for active meetings, render in TeamsISO's UI. In-call mute/cam state is not exposed via Graph as of writing — Phase E.3 would surface participant presence but not mic/cam controls.
  • Teams' UI Automation tree. Walk Teams' window with UIAutomation to read call state. Brittle but usable; what other "Teams remote" tools do.

Implementation effort: a week per route. Recommend Graph for read paths, UIAutomation for write paths.

Out of scope (for now)

  • Hosting the actual meeting media stack (audio/video render, mixer, network). Teams owns this and we don't want to.
  • Replacing Teams entirely with our own SIP/WebRTC stack. That's a different product.

Decision required

User to confirm:

  1. Phase E.1 first (just launcher + group routing). Yes/no.
  2. Whether to use ms-teams: URI launch or the new MSTeams.exe binary path (%LOCALAPPDATA%\Microsoft\WindowsApps\ms-teams.exe).
  3. Whether to ship NDI Access Manager config writes, or just document the manual steps and trust the user to set them once.

Implementation log

  • 2026-05-08: First version of this spec drafted while user is asleep.
  • 2026-05-08: Phase E.1 partial — "Launch Teams" rail button shipped (commit pending). Group-routing automation deferred until user confirms approach.