Adds an NdiGroupSettings record carrying optional comma-separated NDI group lists for the finder and the senders. Extends INdiInterop.CreateFinder / CreateSender with optional groups arguments and populates NDIlib_find_create_t.p_groups and NDIlib_send_create_t.p_groups via P/Invoke. IsoController reads the settings on construction, threads DiscoveryGroups into NdiDiscoveryService and OutputGroups into IsoPipelineConfig, and exposes SetGroupSettingsAsync for runtime updates (group changes apply on next process restart so live pipelines aren't orphaned).
This unblocks the 'transcoder' topology where Teams broadcasts NDI on a private group (e.g. teamsiso-input) and TeamsISO re-emits clean normalized streams on Public — keeping raw, wrong-framerate Teams sources off the production network.
EngineConfig schema is JSON-back-compat: existing config.json files (no NdiGroups field) deserialize with NdiGroups=null and load as NdiGroupSettings.Default. UI surface for these settings comes in a follow-up.
Tests: 72/72 passing (was 69) — added IsoController coverage that group settings are read from ConfigStore on startup, passed to the finder, threaded into per-pipeline config, and round-trip through SetGroupSettingsAsync/Save/Load.
Enumerates every raw NDI source string visible to the local NDI finder for ~5 seconds and prints unique ones, then exits. Bypasses NdiSourceParser so it surfaces sources that the parser would otherwise reject — useful for confirming the on-the-wire format Teams (or any other producer) is actually emitting on a given setup.
Used directly to diagnose the Teams 'MS Teams' vs. 'Teams' brand-prefix mismatch fixed in the previous commit; left in as a permanent debug tool for future setup issues.
The new Microsoft Teams desktop client (observed against a live meeting on Teams 26106.1906.4665.7308) emits NDI source strings of the form
WOOGLIN (MS Teams - Brendon Power)
WOOGLIN (MS Teams - (Local))
WOOGLIN (MS Teams - Active Speaker)
rather than the legacy 'MACHINE (Teams - ...)' shape NdiSourceParser was written to. As a result every Teams source was rejected and TeamsISO showed zero participants in real meetings.
Refactor the parser to recognize 'Teams', 'MS Teams', and (defensively) 'Microsoft Teams' as brand prefixes — longest first so 'MS Teams' isn't shadowed. Also recognize reserved suffix tokens after a dash ('Active Speaker' / 'Audio' / 'Audio Mix' / 'Screen Share') so the new active-speaker output is correctly classified as ActiveSpeaker rather than misread as a participant named 'Active Speaker'.
Tests: kept all legacy cases, added MS Teams + Microsoft Teams variants and the new dash-prefixed reserved-suffix cases. 69/69 unit tests passing; verified end-to-end against a live Teams meeting where TeamsISO.exe now shows '(Local)' and 'Brendon Power' in the Participants DataGrid.
Shipping NDI 6 reports its version as a build banner of the form
NDI SDK WIN64 13:07:00 Jun 2 2025 6.2.0.3
not the 'NDI SDK for Windows v6.x.x.x' format the prefix constant assumed. As a result NdiRuntimeProbe raised a spurious mismatch alert on every supported install. Update ExpectedRuntimeVersionPrefix to 'NDI SDK WIN64' which is the stable architecture token in the new banner; the trailing four-part version remains available for a stricter major-version check if that becomes useful.
The NDI 6 installer sets NDI_RUNTIME_DIR_V6 (and V5/V4 for back-compat) but does not always add the runtime directory to PATH, so a default DllImport(Processing.NDI.Lib.x64) failed with 0x8007007E (DllNotFoundException) on otherwise correctly installed machines, killing both TeamsISO.exe and TeamsISO.Console at preflight.
Add NdiNativeLibraryResolver, registered from NdiNative's static ctor, that resolves the DLL by trying NDI_RUNTIME_DIR_V6 / V5 / V4 in order, NativeLibrary.Load-ing the file from disk before the runtime falls back to its default search algorithm. Static-ctor registration (rather than [ModuleInitializer]) sidesteps CA2255 under TreatWarningsAsErrors and still guarantees the resolver is in place before the first P/Invoke fires.
MSBuild on Windows compares solution-filter project paths against .sln entries as raw strings, so the forward-slash entries in TeamsISO.Windows.slnf / TeamsISO.Linux.slnf were being rejected (MSB5028) against the .sln's backslash entries. Linux dotnet normalizes separators so CI happened to be green. Switch the .sln to forward slashes so both platforms agree; Visual Studio accepts either form.
- TeamsISO.App: hand-rolled net8.0-windows WPF csproj since the WPF
template isn't shipped on linux-arm64 .NET SDK; UI is a placeholder
for Phase C.
- TeamsISO.Engine.IntegrationTests: cross-platform xunit project with a
skipped scaffold fact tagged [Trait("requires", "ndi")] for Phase B.
- TeamsISO.Linux.slnf: solution filter for non-Windows CI that excludes
the WPF project (which can only build on Windows).