diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..0d82788 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,168 @@ +# Changelog + +All notable changes to TeamsISO are documented here. The format follows +[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project +adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added — May 2026 feature batch + +#### Engine +- NDI Groups: discovery + sender support so Teams' raw broadcasts can be + pinned to a private "teamsiso-input" group while TeamsISO's own + normalized outputs broadcast on Public. +- One-click "Apply transcoder topology" writes `ndi-config.v1.json` so all + Teams broadcasts go to the private group and TeamsISO re-emits on Public. +- `RawBgraRecorderSink` per-output recorder: `IRecorderSink` interface + + raw BGRA stream + `manifest.json` + `convert.cmd` script for FFmpeg + conversion to H.264 MKV. +- Recording markers: `IRecorderSink.AddMarker(label)` fan-out via + `IIsoController.AddRecordingMarker`. Markers land in `manifest.json` + under `markers[]` for post-production chaptering. +- Preview thumbnails: `IsoPipeline.LatestProcessedFrame` published via + `Volatile.Read` so the UI can render 160×90 BGRA thumbnails in the + participants DataGrid at 1Hz. +- Idempotent `ParticipantTracker.HandleAdded`: re-emitting Added for an + already-live source refreshes LastSeen instead of duplicating the row. + Fixes the "click Refresh and rows ghost-duplicate" bug introduced by + the Refresh-Discovery affordance. +- `IIsoController.RefreshDiscovery()` rebuilds the NDI finder on the next + poll tick — useful right after applying a new transcoder topology. +- `IIsoController.AddRecordingMarker(label)` fan-out to every active recorder. +- `IIsoController.SetRecording(enabled, dir)` global recording toggle; + per-participant override via `EnableIsoAsync(...recordOverride...)`. + +#### Host (WPF) +- Active Speaker as a synthetic routable participant with deterministic v5 + GUID derived from `auto-mix:`. +- Auto-disable on departure: when a participant's NDI source disappears, + optionally tear down their pipeline. +- Operator presets: chromeless `Presets…` dialog with Save / Apply / + Delete / Duplicate / Export / Import. Persisted at + `%LOCALAPPDATA%\TeamsISO\presets.json`. Bundle format + `teamsiso-presets-bundle/v1` for migration between machines. +- Auto-apply last preset on launch (configurable, off by default). +- `--apply-preset NAME` CLI flag for desktop-shortcut workflows. +- `PresetApplier` — single source of truth for "apply preset to live + participants" used by the dialog, REST surface, and auto-apply path. +- Live preview thumbnails per participant (160×90 BGRA WriteableBitmap). +- Right-click context menu on participant rows: Toggle ISO, Record-this- + participant, Copy NDI source name. +- Live filter input (substring match on display name). +- "Enable all online" + "Stop all ISOs" + "Refresh" header actions. +- Per-participant recording opt-out checkbox (Rec column). +- Custom NDI output name template with `{name}`/`{guid}`/`{machine}`/ + `{timestamp}` tokens. +- Phase E.1 — Launcher: rail "Launch / Stop Teams" toggle. +- Phase E.2 — Window orchestration: hide / show Teams windows from the rail. +- Phase E.3 — In-call controls (UIA): Mute, Camera, Share, Leave, Raise hand, + plus PostMessage shortcut forwarding fallback. Candidate names localized + for English / German / Spanish / French / Portuguese / Japanese. +- Crash diagnostics: AppDomain + Dispatcher + TaskScheduler unhandled + exception handlers wired to Serilog.Critical + user-facing dialog. +- First-launch onboarding dialog with 5-step setup checklist. +- About dialog gained "Show welcome", "Check for updates", "Export diagnostics" + buttons. +- Diagnostic bundle export: zips logs + config + presets + version metadata + into `~/Downloads/teamsiso-diagnostics-.zip` for bug reports. +- Update check: manual via About + auto-on-launch banner (throttled to 24h, + opt-out via flag file at `%LOCALAPPDATA%\TeamsISO\no-update-check.flag`). +- Disk space watcher auto-disables recording at <1GB free. +- Settings panel refactored into OUTPUT / NETWORK / DISPLAY tabs. +- Reset-to-defaults button in OUTPUT tab. +- Enriched footer: REC badge, control-surface badge, session timer (HH:MM:SS + since first ISO went live), dynamic status text ("3/5 ISOs live · 2 recording"). +- Window-scoped keyboard shortcuts: F1 (help), Ctrl+M (marker), Ctrl+Shift+S + (stop all), Ctrl+R (refresh discovery). +- F1 help / cheat-sheet dialog. +- `UIPreferences` static persists `HideLocalSelf`, `AutoDisableOnDeparture`, + `ParticipantSort` (JoinOrder / Alphabetical / OnlineFirst) across launches + to `%LOCALAPPDATA%\TeamsISO\ui-prefs.json`. +- Pop-out per-participant preview window (right-click → Open preview…) + refreshes at ~20Hz and is multi-monitor friendly. +- Configurable participant sort order via the DISPLAY tab dropdown. +- Stop-All confirms before tearing down running pipelines (catches + mid-show misclicks). +- About dialog gained "Logs / Recordings / Notes" folder shortcut buttons. +- `NotesWindow` inline viewer for today's show-notes file with 2s polling. +- Duplicate-preset action in the Presets dialog with smart `(copy N)` + name suggestions. +- `--apply-preset NAME` command-line flag for desktop-shortcut workflows. +- New `TeamsISO.App.Tests` net8.0-windows test project. Initial coverage: + `OperatorPresetStoreTests` (round-trip, name collisions, schema, bundle + import/export, garbage-file resilience), `OutputNameTemplateTests` (token + expansion + sanitization), `OscMessageTests` (wire-format parsing of + int/float/string/T/F type tags). Backed by an `InternalsVisibleTo` grant + + a test-only `OperatorPresetStore.PathOverride` hook. +- `IsoHealthStats.PeakAudioLevel` field + DataGrid VU-bar UI scaffolding. + Engine still emits 0.0 (audio capture is a focused follow-up); the bar's + decay logic is in place so it animates as soon as engine-side audio + parsing lands. +- `MediaFoundationRecorderSink` scaffold under `#if MF_AVAILABLE` for + inline H.264 encoding via Vortice.MediaFoundation. ~10× smaller files + than the raw BGRA recorder. Activation steps documented at + `docs/REAL-TIME-RECORDING.md`. +- System-tray icon + minimize-to-tray toggle. Adds + `true` for `NotifyIcon`; the + `TrayIconHost` lives on `App` (process lifetime, not main-window + lifetime). Right-click menu has Show / Stop all ISOs / Exit. +- Built-in NDI test pattern: `TeamsISO.Console --test-pattern` broadcasts + a synthetic 1280×720 30fps source named `TEAMSISO_TEST` showing SMPTE + color bars + a moving sweep band. Verifies NDI runtime, sender + configuration, and downstream discovery without needing Teams running. + Backed by `TestPatternGenerator` in the engine + 4 unit tests covering + buffer size, alpha, color distinctness, and sweep animation. +- Always-toast on participant disconnect, regardless of `AutoDisableOnDeparture` + setting. Distinguishes "ISO torn down" (auto-disable on) from "ISO still + running on slate" (auto-disable off) so operators don't miss a silent + drop mid-show. +- **Restart this ISO** right-click action — disable + brief delay + re-enable + for one participant only. Useful when a single feed flakes without + affecting other ISOs. +- **Roll recording** action: rolls every active recording into a new chunk + (disable + re-enable each pipeline; recorder finalizes its `manifest.json` + and starts a fresh subdirectory). Surfaced via `MainViewModel.RollRecordingCommand`, + REST `POST /recording/roll`, and OSC `/teamsiso/recording/roll`. Useful + for chaptering between show segments. + +#### Control surface +- REST API on `127.0.0.1:9755` with endpoints for participant ISO toggle (by + Id or display name), preset apply, refresh discovery, stop-all, recording + on/off, marker drop, notes, and Teams in-call commands. Documented at + `docs/CONTROL-SURFACE.md`. +- WebSocket `/ws` pushes live participant state at 4Hz with snapshot diffing. +- OSC bridge on UDP `127.0.0.1:9000` mirrors the REST vocabulary + (`/teamsiso/iso "Jane" 1`, `/teamsiso/preset "..."`, etc.). +- Embedded HTML control panel at `GET /ui` — phone-friendly remote with + live state and one-click action buttons. +- Show notes service: `POST /notes` and `/teamsiso/notes "..."` append + timestamped lines to `%LOCALAPPDATA%\TeamsISO\Notes\.md`. + +#### CI / Release +- Forgejo CI is green; tag-push release workflow builds + tests + publishes + + builds MSI on a Windows runner and attaches it to the auto-created + release via the REST API. +- Optional MSI + exe code-signing wired into `release.yml` — gated on + `SIGN_CERT_PFX_BASE64` + `SIGN_CERT_PASSWORD` Forgejo Secrets. + +### Fixed + +- `.slnf` path-separator mismatch (forward slashes for cross-platform). +- NDI native DLL resolution via `NativeLibrary` resolver. +- `ExpectedRuntimeVersionPrefix` updated to NDI 6 banner format. +- `NdiSourceParser` accepts current Teams desktop's `MS Teams - ` + brand format. +- ActiveSpeaker source removal no longer poisons the rename-window + heuristic for a Participant joining the same machine within the window. +- `IsoPipeline.State` access synchronized via `Volatile.Read/Write`. +- REST handlers now correctly marshal `ObservableCollection` reads + writes + through the UI dispatcher. +- WebSocket upgrade no longer falls into `res.Close()` finally block (was + killing freshly-upgraded connections). +- `ParticipantViewModel.UpdateThumbnail` defends against malformed frames + (`width*height*4 > Pixels.Length`). +- `HasThumbnail` correctly fires `PropertyChanged` when `Thumbnail` + transitions from null. + +[Unreleased]: https://forge.wilddragon.net/zgaetano/teamsiso/compare/v0.1.0...HEAD