From 8a609fb8f387d5a7a994bdbc0230bbbd2d6ff95a Mon Sep 17 00:00:00 2001 From: John Wallace Date: Mon, 9 Nov 2026 21:31:13 -0500 Subject: [PATCH 1/2] Prepare manual-first RC controls and native fade to black --- COREVIDEO_PRO_PRODUCT_SPEC.md | 6 + README.md | 6 +- .../src/feedbacks.ts | 1 + companion-module-corevideopro/src/presets.ts | 7 + docs/BACKLOG.md | 7 + docs/reference/first-release-scene-control.md | 86 +++ docs/reference/images/rc-studio-controls.png | Bin 0 -> 99433 bytes docs/reference/images/rc-studio-footer.png | Bin 0 -> 17211 bytes .../Sources/CoreVideoProShell/AppModel.swift | 16 +- .../CoreVideoProShell/AutomationExtras.swift | 8 +- .../Sources/CoreVideoProShell/ShellApp.swift | 85 +-- .../CoreVideoProShell/ShellPrefs.swift | 4 +- .../HttpControlRouterTests.cs | 37 +- .../ControlActionRegistry.cs | 7 +- .../CoreVideoPro.Control/ControlState.cs | 1 + .../NativeMediaCoreStateMapperTests.cs | 15 + .../Models/CoreProtocolModels.cs | 2 + .../Models/NativeMediaCoreProtocol.cs | 2 + .../Services/NativeMediaCoreStateMapper.cs | 2 + .../MagicSceneCoordinatorTests.cs | 45 +- .../NativeControlEvidenceTests.cs | 12 - .../Controls/StudioFooterLayoutPanel.cs | 59 +- .../Models/SceneDisplayItem.cs | 11 +- .../Services/StudioControlSurface.cs | 26 +- .../Services/StudioWorkspaceLayoutProbe.cs | 33 +- .../MagicScene/MagicSceneCoordinator.cs | 40 +- .../ViewModels/SceneWorkspaceViewModel.cs | 6 + .../StudioViewModel.GraphicsMode.cs | 2 +- .../StudioViewModel.ProgramBlackout.cs | 72 +++ .../StudioViewModel.TilesNavigation.cs | 16 + .../ViewModels/StudioViewModel.cs | 9 +- .../Views/AutomationPage.xaml | 198 +----- .../Views/SettingsPage.xaml.cs | 6 + .../Views/StudioWorkspace.SceneNaming.cs | 11 + .../Views/StudioWorkspace.TransportHotkeys.cs | 32 + .../Views/StudioWorkspace.xaml | 604 +++++------------- .../Views/StudioWorkspace.xaml.cs | 1 + native/CMakeLists.txt | 1 + native/src/core/CoreStateCapture.cpp | 3 + native/src/core/CoreStateCapture.h | 1 + native/src/core/MediaCore.cpp | 5 + native/src/core/MediaCore.h | 2 + native/src/core/ProgramBlackout.h | 46 ++ native/src/core/Protocol.h | 3 +- native/tests/D3D11CompositorTest.cpp | 27 + native/tests/ProgramBlackoutTest.cpp | 47 ++ scripts/qa/outputs-drill.ps1 | 2 +- 47 files changed, 785 insertions(+), 827 deletions(-) create mode 100644 docs/reference/first-release-scene-control.md create mode 100644 docs/reference/images/rc-studio-controls.png create mode 100644 docs/reference/images/rc-studio-footer.png create mode 100644 native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.ProgramBlackout.cs create mode 100644 native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.TilesNavigation.cs create mode 100644 native-shell/CoreVideoPro.WinUI/Views/StudioWorkspace.TransportHotkeys.cs create mode 100644 native/src/core/ProgramBlackout.h create mode 100644 native/tests/ProgramBlackoutTest.cpp diff --git a/COREVIDEO_PRO_PRODUCT_SPEC.md b/COREVIDEO_PRO_PRODUCT_SPEC.md index 581239358..be9020bc3 100644 --- a/COREVIDEO_PRO_PRODUCT_SPEC.md +++ b/COREVIDEO_PRO_PRODUCT_SPEC.md @@ -1,5 +1,11 @@ # CoreVideo Pro Product Spec and MVP Plan +> **First-release scope, November 9, 2026:** CoreVideo Tiles replaces legacy Magic +> Scene composition. Set & Forget and legacy Magic Scene are excluded and cannot +> be enabled. Scene selection and Take remain manual. Older automation promises +> below are deferred vision, not release acceptance. See +> [first-release scene control](docs/reference/first-release-scene-control.md). + > **Implementation status (2026-06-21).** This document is the product vision and MVP > plan. The shipping architecture is a **WinUI 3 (.NET 9) shell embedding a React/TypeScript > operator UI over a C++20 media core**, **Windows-first** (macOS is a roadmap target, not diff --git a/README.md b/README.md index b53135017..d7833d40e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ CoreVideo Pro is a **native desktop production studio for Windows and macOS** for building polished live shows, recordings, and streams from Zoom participants, cameras, screen capture and -media: Magic Scene auto-layout, lower-thirds, graphics, audio leveling, and +media: CoreVideo Tiles composition, lower-thirds, graphics, audio leveling, and multi-destination output, in a single operator console. **Work order lives in one place:** [`docs/BACKLOG.md`](docs/BACKLOG.md). This README is @@ -93,7 +93,7 @@ the stream, every ISO writer and the camera publisher ran clean, and Program rec | | DeckLink / AJA | Not shipped: probe only ([#537](https://github.com/iamfatness/CoreVideoPro/issues/537)) | | **Media** | Local video and still playback with core-owned cue/live/pause | Shipped, not live-verified; ProRes fails to start in the installed build ([#473](https://github.com/iamfatness/CoreVideoPro/issues/473)); stutter reported ([#701](https://github.com/iamfatness/CoreVideoPro/issues/701)) | | **Compositor** | D3D11 Program/Preview/Multiview, per-source framing, borders, grade presets and curves, lower-thirds and graphics templates | Proven: Program render held every deadline in the soak (minimum slack 3.6 ms) | -| | Set & Forget and Magic Scene automation driven by the core's slot bindings | Shipped, not live-verified: bound in [#1021](https://github.com/iamfatness/CoreVideoPro/pull/1021), unit-tested to the coordinator | +| | Scene selection and Take | Manual control through Studio, keyboard and Stream Deck. Legacy Magic Scene and Set & Forget are excluded from the first release. | | | Captions | Not shipped: the controls were removed in #1021 because no caption source exists; `push-caption-cue` remains for external cue feeds | | **Audio** | Routing matrix, Program and ISO taps, BS.1770 meter, bus dynamics and limiter, WASAPI monitor output | Proven on live shows; recorded Program A/V skew measured near -20 ms, live monitor skew -46 ms after [#655](https://github.com/iamfatness/CoreVideoPro/pull/655) ([#652](https://github.com/iamfatness/CoreVideoPro/issues/652) open on the limit) | | | Per-participant audio delay | Not shipped ([#627](https://github.com/iamfatness/CoreVideoPro/issues/627)) | @@ -180,7 +180,7 @@ The first fully useful milestone: 1. Join Zoom. 2. See clean participant feeds and metadata. -3. Click Magic Scene. +3. Compose the show with CoreVideo Tiles and cue the desired scene on Preview. 4. Get a polished show with lower-thirds, graphics, audio leveling, and stream / local-recording / virtual-camera controls. diff --git a/companion-module-corevideopro/src/feedbacks.ts b/companion-module-corevideopro/src/feedbacks.ts index 16cb2aaa3..87a9da01e 100644 --- a/companion-module-corevideopro/src/feedbacks.ts +++ b/companion-module-corevideopro/src/feedbacks.ts @@ -7,6 +7,7 @@ export interface FlagSource { /** The boolean ControlState fields worth lighting a button. */ export const FEEDBACK_FLAGS: { id: string; name: string; on: number; off?: number }[] = [ + { id: 'programBlackout', name: 'Program faded to black', on: combineRgb(200, 40, 40) }, { id: 'recording', name: 'Recording active', on: combineRgb(200, 40, 40) }, { id: 'streaming', name: 'Streaming active', on: combineRgb(200, 40, 40) }, { id: 'engineOn', name: 'Capture engine on', on: combineRgb(40, 140, 60) }, diff --git a/companion-module-corevideopro/src/presets.ts b/companion-module-corevideopro/src/presets.ts index 7db091228..225382a49 100644 --- a/companion-module-corevideopro/src/presets.ts +++ b/companion-module-corevideopro/src/presets.ts @@ -7,6 +7,13 @@ const black = combineRgb(0, 0, 0) export function buildPresets(): CompanionPresetDefinitions { const presets: CompanionPresetDefinitions = {} + presets['ftb'] = { + type: 'button', category: 'Transport', name: 'Fade to Black', + style: { text: 'FTB', size: '18', color: white, bgcolor: black }, + steps: [{ down: [{ actionId: 'transport.ftb.toggle', options: {} }], up: [] }], + feedbacks: [{ feedbackId: 'programBlackout', options: {}, style: { text: 'BLACK', bgcolor: combineRgb(200, 40, 40) } }], + } + presets['take'] = { type: 'button', category: 'Transport', diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 2172bf660..4a79cb19d 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -1,5 +1,12 @@ # CoreVideo Pro — ranked backlog +**Owner release-scope decision, November 9:** defer the legacy scene director +tracked under [#668](https://github.com/iamfatness/CoreVideoPro/issues/668). +Exclude Set & Forget and old Magic Scene from the first release, including +background and remote activation. Preserve CoreVideo Tiles and manual Take. +Implementation contract: [first-release scene control](reference/first-release-scene-control.md). +This is a release exclusion, not completion of the deferred director's acceptance. + ## Now — Zoom ISO recording size, November 9 | Order | Issue | Scope and acceptance | diff --git a/docs/reference/first-release-scene-control.md b/docs/reference/first-release-scene-control.md new file mode 100644 index 000000000..a131a991b --- /dev/null +++ b/docs/reference/first-release-scene-control.md @@ -0,0 +1,86 @@ +# First-release scene control + +Owner decision, November 9, 2026: exclude Set & Forget and the legacy Magic Scene +workflow from the first release. CoreVideo Tiles owns composition. Scene selection +and Take remain manual through Studio, keyboard, and Stream Deck/Companion. +This supersedes the automation promises in the earlier product and director specs; +it does not change the Tiles speaker-follow or membership policies. + +Windows removes the legacy footer buttons and Automation navigation. A restored +legacy page provides manual-production guidance and the separate free-input filling +setting. The production MagicSceneCoordinator constructor cannot enable scene +automation: commands, direct mode assignments and automatic-Take intent are blocked, +and snapshot/timer evaluation cannot bind Preview, start the timer, change graphics, +or Take. The internal opt-in constructor is solely for deferred-engine unit tests; +there is no user setting, environment variable or license override. + +The remote action catalog no longer advertises automation.magic, automation.toggle +or automation.autoTake.set. Saved HTTP/OSC/Companion commands fail validation instead +of silently re-enabling the feature. The adapter also rejects those legacy IDs if +called directly. Existing clients should remove those buttons. Manual transport.take, +scene controls and Tiles controls remain registered. The outputs drill no longer +sends the retired auto-Take command. + +macOS removes the same controls and navigation. Its immutable release gate prevents +setAutoDirect from starting a timer; the evaluator and one-shot command are guarded. +Legacy auto-Take preferences are ignored. Native macOS build/runtime verification +requires macOS and is not covered by Windows checks. + +Automatic filling of free input slots and the separate native graphics automation +are not the retired scene director and remain available. No installer or saved user +profile is modified by this source change. + +## Studio manual controls + +The Windows Studio footer groups Graphics and Outputs on the left, Take/FTB on the right, above a separate +health/audio row. Output option flyouts remain available. Edit Tiles on a Tiles +scene cues that scene to Preview and opens its wall inspector; it never Takes. + +Ctrl+Enter invokes the existing Take command in Studio. Ctrl+Shift+B invokes FTB. +Both shortcuts ignore text-entry controls. Existing graphics F-key mappings and +remote `transport.take` remain unchanged. Companion discovers `transport.ftb.toggle` +and `transport.ftb.set(enabled)` from the action manifest; its FTB preset lights +from `programBlackout` feedback. Use the idempotent set action when retrying requests. + +FTB fades Program video over 300 ms; pressing again restores the picture from the +current fade level. The core appends a neutral black GPU layer above scene and +global graphics. Preview, source ISOs, audio, and running output sessions are +unchanged. Taking another scene while black does not release the blackout. The +RC button has a black fill with no visible text and a red outline when black is selected. No saved +preference automatically engages FTB; a new media-core session starts clear. +Older cores without the blackout observation reject FTB rather than implying success. + +Layout checks run in an isolated offscreen window. GPU pixel tests prove the native +compositor fade and restoration; these checks are not a live multi-output soak. + +The layout fidelity correction keeps Edit Tiles inside its scene card, separates +Take from the transition selector, arranges Graphics / Outputs / transport as three +measured groups, and gives telemetry its own full-width row. Zoom and Health are +direct top navigation actions. The graphics panel starts closed and the on-air/cued +strip appears with that panel; the Graphics button and function keys remain available. +Scene removal remains in the scene context menu. Background import is available in +the background picker context menu and the scene editor. Layout review builds are +separate from the running application so reviewing them does not restart a meeting. + +The footer keeps the lower-third shortcut but omits the generic Preview graphic / +Show on Program buttons. Show, Cue and Hide remain attached to each graphic in +the Graphics workspace; graphics keyboard and remote actions are unchanged. + +RC footer outputs use compact Record, broadcast, webcam icons and an NDI badge. +Separate option arrows preserve output settings; tooltips and accessible names +identify each action. Take, transition choice, and the black FTB key are anchored +to the far right. Keyboard and remote commands remain unchanged. Manual blend +is excluded from the RC. + +Graphics and output shortcuts form a left-aligned group with a fixed gap; only +the space before Take grows with the window. Output icons use matching 26px +line artwork and neutral idle backgrounds, with record/stream colors reserved +for their active states. + +## Compiled Windows layout + +These captures come from the isolated compiled layout check, with no live video. + +![Studio controls](images/rc-studio-controls.png) + +![Footer close-up](images/rc-studio-footer.png) diff --git a/docs/reference/images/rc-studio-controls.png b/docs/reference/images/rc-studio-controls.png new file mode 100644 index 0000000000000000000000000000000000000000..8941c6035012585c4d1bccb61f577ac3c02f4abe GIT binary patch literal 99433 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 literal 0 HcmV?d00001 diff --git a/docs/reference/images/rc-studio-footer.png b/docs/reference/images/rc-studio-footer.png new file mode 100644 index 0000000000000000000000000000000000000000..c375d60b10fb8034837fac405c72489e67e5b711 GIT binary patch literal 17211 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 Int(model.autoConfidenceThreshold) - ? Studio.accent : Studio.secondary) - Spacer() - Text(model.autoRuleId) - .font(.plexMono(9)) - .foregroundStyle(Studio.secondary) - } - Text(model.autoRationale) - .font(.grotesk(11)).foregroundStyle(Studio.secondary) - } - // AutomationPage.xaml parity: Magic Scene, dynamic lower thirds, - // reset defaults, the scene-intelligence readouts, and the honest - // disabled block. Lives in AutomationExtras.swift. - AutomationExtrasSection() + Text("Manual production").font(.grotesk(14, .semibold)) + Text("Scene automation is unavailable in this release. Compose your show and use manual Take.").font(.grotesk(12)) } .modifier(StudioPanel()) } diff --git a/mac-shell/Sources/CoreVideoProShell/ShellPrefs.swift b/mac-shell/Sources/CoreVideoProShell/ShellPrefs.swift index 5cb68e39e..6c5970b11 100644 --- a/mac-shell/Sources/CoreVideoProShell/ShellPrefs.swift +++ b/mac-shell/Sources/CoreVideoProShell/ShellPrefs.swift @@ -62,7 +62,7 @@ struct ShellPrefs: Codable, Equatable { var monitorVolume = 0.7 var isoRecordingEnabled = false var isoSelectedSourceIds: [String] = [] - var autoTakeEnabled = true + var autoTakeEnabled = false var autoConfidenceThreshold = 70.0 var autoHoldSeconds = 4.0 // Automation-tab policy (AutomationExtras.swift). OPTIONAL on purpose: a @@ -116,7 +116,7 @@ struct ShellPrefs: Codable, Equatable { monitorVolume = v(.monitorVolume, 0.7) isoRecordingEnabled = v(.isoRecordingEnabled, false) isoSelectedSourceIds = v(.isoSelectedSourceIds, []) - autoTakeEnabled = v(.autoTakeEnabled, true) + autoTakeEnabled = false // Retired scene automation cannot be restored from preferences. autoConfidenceThreshold = v(.autoConfidenceThreshold, 70.0) autoHoldSeconds = v(.autoHoldSeconds, 4.0) lowerThirdName = v(.lowerThirdName, "") diff --git a/native-shell/CoreVideoPro.Control.Tests/HttpControlRouterTests.cs b/native-shell/CoreVideoPro.Control.Tests/HttpControlRouterTests.cs index 59e359587..e30ac33b5 100644 --- a/native-shell/CoreVideoPro.Control.Tests/HttpControlRouterTests.cs +++ b/native-shell/CoreVideoPro.Control.Tests/HttpControlRouterTests.cs @@ -57,9 +57,13 @@ public async Task Get_Manifest_ReturnsTheActionContract() Assert.Equal(200, response.Status); Assert.Contains("transport.take", response.Body); + Assert.Contains("transport.ftb.toggle", response.Body); + Assert.Contains("transport.ftb.set", response.Body); Assert.Contains("scene.cueWithRoutes", response.Body); Assert.Contains("scene.route.set", response.Body); - Assert.Contains("automation.magic", response.Body); + Assert.DoesNotContain("automation.magic", response.Body); + Assert.DoesNotContain("automation.toggle", response.Body); + Assert.DoesNotContain("automation.autoTake.set", response.Body); Assert.Contains("/cvp/transport/take", response.Body); } @@ -71,6 +75,7 @@ public async Task Get_State_ReturnsCamelCaseState() State = ControlState.Empty with { Recording = true, + ProgramBlackout = true, ActiveSceneId = "interview", ZoomAudioMode = "perGuestIso", ProgramTruePeakDbfs = -8.5, @@ -84,6 +89,7 @@ public async Task Get_State_ReturnsCamelCaseState() Assert.Equal(200, response.Status); using var doc = JsonDocument.Parse(response.Body); Assert.True(doc.RootElement.GetProperty("recording").GetBoolean()); + Assert.True(doc.RootElement.GetProperty("programBlackout").GetBoolean()); Assert.Equal("interview", doc.RootElement.GetProperty("activeSceneId").GetString()); Assert.Equal("perGuestIso", doc.RootElement.GetProperty("zoomAudioMode").GetString()); Assert.Equal(-8.5, doc.RootElement.GetProperty("programTruePeakDbfs").GetDouble()); @@ -92,6 +98,22 @@ public async Task Get_State_ReturnsCamelCaseState() Assert.Equal(-6.2, source.GetProperty("peakDbfs").GetDouble()); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task FadeToBlackSetRoutesBooleanIntentAndReportsNativeFailure(bool enabled) + { + var surface = new FakeControlSurface { Handler = (_, _) => ControlInvokeResult.Fail("core offline") }; + var response = await new HttpControlRouter(surface).HandleAsync("POST", "/invoke", + JsonSerializer.Serialize(new { action = "transport.ftb.set", args = new[] { enabled } })); + var invocation = Assert.Single(surface.Invocations); + Assert.Equal("transport.ftb.set", invocation.ActionId); + Assert.Equal(enabled, invocation.Args[0]); + Assert.Contains("core offline", response.Body); + using var json = JsonDocument.Parse(response.Body); + Assert.False(json.RootElement.GetProperty("ok").GetBoolean()); + } + [Fact] public async Task Post_Invoke_BindsArgsAndInvokesTheSurface() { @@ -168,6 +190,19 @@ public async Task Post_Invoke_Returns422WhenSurfaceFails() Assert.Contains("slot out of range", response.Body); } + [Theory] + [InlineData("automation.magic")] + [InlineData("automation.toggle")] + [InlineData("automation.autoTake.set")] + public async Task LegacySceneAutomationCannotBeInvokedBySavedRemoteButtons(string action) + { + var surface = new FakeControlSurface(); + var router = new HttpControlRouter(surface); + var body = JsonSerializer.Serialize(new { action, args = new object[] { true } }); + Assert.Equal(400, (await router.HandleAsync("POST", "/invoke", body)).Status); + Assert.Empty(surface.Invocations); + } + [Fact] public async Task UnknownRoute_Returns404() { diff --git a/native-shell/CoreVideoPro.Control/ControlActionRegistry.cs b/native-shell/CoreVideoPro.Control/ControlActionRegistry.cs index cd0a9febc..70e92696f 100644 --- a/native-shell/CoreVideoPro.Control/ControlActionRegistry.cs +++ b/native-shell/CoreVideoPro.Control/ControlActionRegistry.cs @@ -52,6 +52,9 @@ private static IReadOnlyList BuildActions() new("zoom.leave", "Leave Zoom", "Leave the current embedded Zoom meeting."), // ---- Transport -------------------------------------------------------------- + new("transport.ftb.toggle", "Fade to Black", "Fade Program video to black or back in over 300 ms. Audio and output sessions continue."), + new("transport.ftb.set", "Set Fade to Black", "Set Program blackout; repeated identical requests do not reverse the fade.", + new[] { new ControlParam("enabled", b, true) }), new("transport.take", "Take", "Cut/transition Preview to Program."), new("transport.transition.set", "Set transition", "Set the Take transition (cut/fade/dip/wipe).", new[] { new ControlParam("mode", s, true, "cut | fade | dip | wipe") }), @@ -304,10 +307,6 @@ [new ControlParam("clip", s, true, "Staged clip key")]), new[] { new ControlParam("on", b, true) }), // ---- Automation ------------------------------------------------------------- - new("automation.magic", "Magic Scene", "Run the one-shot Magic Scene command using the current source roster."), - new("automation.toggle", "Automation toggle", "Toggle production automation on/off."), - new("automation.autoTake.set", "Auto-take", "Toggle automation auto-take.", - new[] { new ControlParam("on", b, true) }), new("automation.autoAssignInputs.set", "Auto-assign inputs", "Toggle auto-assigning roster participants to Show Inputs.", new[] { new ControlParam("on", b, true) }), new("automation.lowerThirds.set", "Auto lower-thirds", "Toggle automation lower-thirds.", diff --git a/native-shell/CoreVideoPro.Control/ControlState.cs b/native-shell/CoreVideoPro.Control/ControlState.cs index 7985f0fd9..075719c09 100644 --- a/native-shell/CoreVideoPro.Control/ControlState.cs +++ b/native-shell/CoreVideoPro.Control/ControlState.cs @@ -53,6 +53,7 @@ public sealed record ControlState public bool Streaming { get; init; } public bool EngineOn { get; init; } public bool CanTake { get; init; } + public bool ProgramBlackout { get; init; } public bool LowerThirdOnAir { get; init; } public string ZoomStatus { get; init; } = string.Empty; diff --git a/native-shell/CoreVideoPro.MediaCore.Tests/NativeMediaCoreStateMapperTests.cs b/native-shell/CoreVideoPro.MediaCore.Tests/NativeMediaCoreStateMapperTests.cs index 1d0302ee9..015dddfa7 100644 --- a/native-shell/CoreVideoPro.MediaCore.Tests/NativeMediaCoreStateMapperTests.cs +++ b/native-shell/CoreVideoPro.MediaCore.Tests/NativeMediaCoreStateMapperTests.cs @@ -7,6 +7,21 @@ namespace CoreVideoPro.MediaCore.Tests; public sealed class NativeMediaCoreStateMapperTests { + [Theory] + [InlineData(true, 0.5)] + [InlineData(false, 0.25)] + public void ProgramBlackoutRoundTripsNativeObservation(bool enabled, double opacity) + { + using var response = JsonDocument.Parse(JsonSerializer.Serialize(new { ok = true, + snapshot = new { health = (object?)null, profile = (object?)null, programBlackout = enabled, programBlackoutOpacity = opacity } })); + var wire = CoreProtocolParser.TryParseWireState(response); + Assert.NotNull(wire); + var snapshot = NativeMediaCoreStateMapper.MapNativeWireStateToSnapshot(0, 0, wire); + Assert.Equal(enabled, snapshot.ProgramBlackout); + Assert.Equal(opacity, snapshot.ProgramBlackoutOpacity); + Assert.Null(new NativeMediaCoreStateSnapshot().ProgramBlackout); + } + [Theory] [InlineData("snapshot")] [InlineData("state")] diff --git a/native-shell/CoreVideoPro.MediaCore/Models/CoreProtocolModels.cs b/native-shell/CoreVideoPro.MediaCore/Models/CoreProtocolModels.cs index 33dfd4690..e1072fc58 100644 --- a/native-shell/CoreVideoPro.MediaCore/Models/CoreProtocolModels.cs +++ b/native-shell/CoreVideoPro.MediaCore/Models/CoreProtocolModels.cs @@ -351,6 +351,8 @@ public sealed class RawParticipantEvent public sealed class NativeMediaCoreWireState { + public bool? ProgramBlackout { get; init; } + public double ProgramBlackoutOpacity { get; init; } public System.Text.Json.JsonElement? ProgramBuffer { get; init; } public NativeMediaCoreProgramFrame? ProgramFrame { get; init; } public NativeMediaCorePreviewScene? PreviewScene { get; init; } diff --git a/native-shell/CoreVideoPro.MediaCore/Models/NativeMediaCoreProtocol.cs b/native-shell/CoreVideoPro.MediaCore/Models/NativeMediaCoreProtocol.cs index f19b3019a..fbad9e3a2 100644 --- a/native-shell/CoreVideoPro.MediaCore/Models/NativeMediaCoreProtocol.cs +++ b/native-shell/CoreVideoPro.MediaCore/Models/NativeMediaCoreProtocol.cs @@ -942,6 +942,8 @@ public sealed record NativeZoomGuestAvSyncAck public sealed record NativeMediaCoreStateSnapshot { + public bool? ProgramBlackout { get; init; } + public double ProgramBlackoutOpacity { get; init; } /// Latest admitted engine capture observation; absent peers remain unknown. public bool? RawMediaActive { get; init; } public AudioOwnerObservation? AudioObservation { get; init; } diff --git a/native-shell/CoreVideoPro.MediaCore/Services/NativeMediaCoreStateMapper.cs b/native-shell/CoreVideoPro.MediaCore/Services/NativeMediaCoreStateMapper.cs index 8f8bc56f8..4445b2586 100644 --- a/native-shell/CoreVideoPro.MediaCore/Services/NativeMediaCoreStateMapper.cs +++ b/native-shell/CoreVideoPro.MediaCore/Services/NativeMediaCoreStateMapper.cs @@ -172,6 +172,8 @@ public static NativeMediaCoreStateSnapshot MapNativeWireStateToSnapshot( return baseSnapshot with { + ProgramBlackout = wire.ProgramBlackout, + ProgramBlackoutOpacity = wire.ProgramBlackoutOpacity, CaptureDevices = wire.CaptureDevices ?? baseSnapshot.CaptureDevices, ProgramBuffer = wire.ProgramBuffer is { ValueKind: JsonValueKind.Object } programBuffer ? programBuffer.Clone() : null, PreviewScene = wire.PreviewScene, diff --git a/native-shell/CoreVideoPro.WinUI.Tests/MagicSceneCoordinatorTests.cs b/native-shell/CoreVideoPro.WinUI.Tests/MagicSceneCoordinatorTests.cs index 663566bbd..366716832 100644 --- a/native-shell/CoreVideoPro.WinUI.Tests/MagicSceneCoordinatorTests.cs +++ b/native-shell/CoreVideoPro.WinUI.Tests/MagicSceneCoordinatorTests.cs @@ -102,10 +102,53 @@ public void DiagnosticPreservesTheObservedHoldAndDoesNotActuateWhenRead() private static (MagicSceneCoordinator Coordinator, FakeMagicSceneHost Host) Build(Func? clock = null) { var host = new FakeMagicSceneHost { Scenes = Scenes }; - var coordinator = new MagicSceneCoordinator(host, clock); + var coordinator = new MagicSceneCoordinator(host, clock, sceneAutomationAvailable: true); return (coordinator, host); } + [Fact] + public void ReleaseConstructorCannotActivateLegacyAutomationThroughAnyEntryPoint() + { + var host = new FakeMagicSceneHost { Scenes = Scenes, RoomVideoParticipantCount = 4, CanTake = true }; + var coordinator = new MagicSceneCoordinator(host); + coordinator.Recommendation = Recommendation("interview", 99); + coordinator.RunMagicSceneCommand.Execute(null); + coordinator.ToggleAutomationCommand.Execute(null); + coordinator.ProductionMode = ProductionMode.SetAndForget; + coordinator.AutomationAutoTakeEnabled = true; + coordinator.ResetAutomationDefaultsCommand.Execute(null); + coordinator.EvaluateAutomationPolicy(); + Assert.Equal(ProductionMode.Manual, coordinator.ProductionMode); + Assert.False(coordinator.AutomationAutoTakeEnabled); + Assert.Equal(0, host.Timer.StartCount); + Assert.Empty(host.PreviewBindings); + Assert.Equal("intro", host.PreviewSceneId); + Assert.Equal("intro", host.ActiveSceneId); + Assert.Equal(0, host.TakeAsyncCallCount); + Assert.Equal(0, host.GraphicPolicyCalls); + Assert.Contains("unavailable", coordinator.AutomationLastAction); + } + + [Fact] + public async Task DisabledDirectorLeavesManualTakeAndItsStatusAloneAcrossRefreshes() + { + var host = new FakeMagicSceneHost { Scenes = Scenes, RoomVideoParticipantCount = 4, CanTake = true }; + var coordinator = new MagicSceneCoordinator(host); + host.PreviewSceneId = "interview"; + await host.TakeAsync(); + ((IMagicSceneHost)host).CommandStatus = "Manual Take completed"; + coordinator.Recommendation = Recommendation("panel", 99); + coordinator.EvaluateAutomationPolicy(); + host.CoreEpoch = "restarted-core"; + host.RosterEpoch = "new-meeting"; + coordinator.EvaluateAutomationPolicy(); + Assert.Equal("interview", host.ActiveSceneId); + Assert.Equal("interview", host.PreviewSceneId); + Assert.Equal("Manual Take completed", host.CommandStatus); + Assert.Equal(1, host.TakeAsyncCallCount); + Assert.Equal(0, host.Timer.StartCount); + } + [Fact] public void SerializedNativeShotWithCurrentPolicyCuesAndTakesTheIntendedGuests() { diff --git a/native-shell/CoreVideoPro.WinUI.Tests/NativeControlEvidenceTests.cs b/native-shell/CoreVideoPro.WinUI.Tests/NativeControlEvidenceTests.cs index 93f5ed877..7df2d9cf8 100644 --- a/native-shell/CoreVideoPro.WinUI.Tests/NativeControlEvidenceTests.cs +++ b/native-shell/CoreVideoPro.WinUI.Tests/NativeControlEvidenceTests.cs @@ -125,18 +125,6 @@ public void ExistingPreviewSceneWireFieldDeserializesIntoEvidence() Assert.Equal("preview", state.NativePreviewSceneId); } - [Fact] - public void MagicApiInvokesTheExistingCommandOnlyWhenAvailable() - { - var available = false; - var calls = 0; - var command = new RelayCommand(() => calls++, () => available); - Assert.False(StudioControlSurface.RunMagicScene(command).Ok); - Assert.Equal(0, calls); - available = true; - Assert.True(StudioControlSurface.RunMagicScene(command).Ok); - Assert.Equal(1, calls); - } [Fact] public void LastRenderedFrameRemainsDistinctFromAcknowledgedScene() { diff --git a/native-shell/CoreVideoPro.WinUI/Controls/StudioFooterLayoutPanel.cs b/native-shell/CoreVideoPro.WinUI/Controls/StudioFooterLayoutPanel.cs index e2ad4f18e..6f1036b46 100644 --- a/native-shell/CoreVideoPro.WinUI/Controls/StudioFooterLayoutPanel.cs +++ b/native-shell/CoreVideoPro.WinUI/Controls/StudioFooterLayoutPanel.cs @@ -4,45 +4,46 @@ namespace CoreVideoPro.WinUI.Controls; -// Keep the existing automation, transport and telemetry groups intact. Decide -// from measured content width, rather than the monitor size or display scale. +// Graphics, outputs, manual transport at the right edge, then full-width telemetry. +// Keep graphics and outputs together; spare space precedes the right-hand transport. public sealed class StudioFooterLayoutPanel : Panel { - private const double Gap = 8, RowGap = 6; - protected override Size MeasureOverride(Size availableSize) + private const double Gap = 12, RowGap = 12; + protected override Size MeasureOverride(Size available) { - if (Children.Count != 3) return base.MeasureOverride(availableSize); - Children[0].Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); - Children[1].Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); - Children[2].Measure(new Size(availableSize.Width, double.PositiveInfinity)); - var left = Children[0].DesiredSize; var transport = Children[1].DesiredSize; - var stacked = left.Width + Gap + transport.Width > availableSize.Width; - var actionsHeight = stacked ? left.Height + RowGap + transport.Height : Math.Max(left.Height, transport.Height); - return new Size(double.IsInfinity(availableSize.Width) ? left.Width + Gap + transport.Width : availableSize.Width, - actionsHeight + RowGap + Children[2].DesiredSize.Height); + if (Children.Count != 4) return base.MeasureOverride(available); + for (var i = 0; i < 3; i++) Children[i].Measure(new(double.PositiveInfinity, double.PositiveInfinity)); + Children[3].Measure(new(available.Width, double.PositiveInfinity)); + var g = Children[0].DesiredSize; var o = Children[1].DesiredSize; var t = Children[2].DesiredSize; + var wrap = g.Width + t.Width + o.Width + Gap * 2 > available.Width; + var height = wrap ? g.Height + RowGap + Math.Max(t.Height, o.Height) : Math.Max(g.Height, Math.Max(t.Height, o.Height)); + return new(double.IsInfinity(available.Width) ? g.Width + t.Width + o.Width + Gap * 2 : available.Width, + height + RowGap + Children[3].DesiredSize.Height); } - - protected override Size ArrangeOverride(Size finalSize) + protected override Size ArrangeOverride(Size final) { - if (Children.Count != 3) return base.ArrangeOverride(finalSize); - var left = Children[0].DesiredSize; var transport = Children[1].DesiredSize; - var stacked = left.Width + Gap + transport.Width > finalSize.Width; + if (Children.Count != 4) return base.ArrangeOverride(final); + var g = Children[0].DesiredSize; var o = Children[1].DesiredSize; var t = Children[2].DesiredSize; + var wrap = g.Width + t.Width + o.Width + Gap * 2 > final.Width; + var rowHeight = Math.Max(t.Height, o.Height); double telemetryTop; - if (stacked) + if (wrap) { - Children[0].Arrange(new Rect(0, 0, finalSize.Width, left.Height)); - Children[1].Arrange(new Rect(Math.Max(0, (finalSize.Width - transport.Width) / 2), left.Height + RowGap, transport.Width, transport.Height)); - telemetryTop = left.Height + RowGap + transport.Height + RowGap; + Children[0].Arrange(new(0, 0, g.Width, g.Height)); + var top = g.Height + RowGap; + Children[1].Arrange(new(0, top + rowHeight - o.Height, o.Width, o.Height)); + Children[2].Arrange(new(Math.Max(o.Width + Gap, final.Width - t.Width), top + rowHeight - t.Height, t.Width, t.Height)); + telemetryTop = top + rowHeight + RowGap; } else { - var height = Math.Max(left.Height, transport.Height); - Children[0].Arrange(new Rect(0, 0, left.Width, height)); - var remaining = finalSize.Width - left.Width - Gap; - Children[1].Arrange(new Rect(left.Width + Gap + (remaining - transport.Width) / 2, 0, transport.Width, height)); - telemetryTop = height + RowGap; + rowHeight = Math.Max(g.Height, rowHeight); + Children[0].Arrange(new(0, rowHeight - g.Height, g.Width, g.Height)); + Children[1].Arrange(new(g.Width + Gap, rowHeight - o.Height, o.Width, o.Height)); + Children[2].Arrange(new(final.Width - t.Width, rowHeight - t.Height, t.Width, t.Height)); + telemetryTop = rowHeight + RowGap; } - Children[2].Arrange(new Rect(0, telemetryTop, finalSize.Width, Children[2].DesiredSize.Height)); - return finalSize; + Children[3].Arrange(new(0, telemetryTop, final.Width, Children[3].DesiredSize.Height)); + return final; } } diff --git a/native-shell/CoreVideoPro.WinUI/Models/SceneDisplayItem.cs b/native-shell/CoreVideoPro.WinUI/Models/SceneDisplayItem.cs index 5f04958ef..23e9644a6 100644 --- a/native-shell/CoreVideoPro.WinUI/Models/SceneDisplayItem.cs +++ b/native-shell/CoreVideoPro.WinUI/Models/SceneDisplayItem.cs @@ -13,7 +13,7 @@ public sealed class SceneDisplayItem new(Windows.UI.Color.FromArgb(255, 61, 220, 151)); private static readonly SolidColorBrush ProgramBorder = - new(Windows.UI.Color.FromArgb(255, 240, 168, 92)); + new(Windows.UI.Color.FromArgb(255, 192, 61, 65)); private static readonly SolidColorBrush DefaultBackground = new(Windows.UI.Color.FromArgb(255, 16, 22, 30)); @@ -22,7 +22,7 @@ public sealed class SceneDisplayItem new(Windows.UI.Color.FromArgb(255, 18, 36, 30)); private static readonly SolidColorBrush ProgramBackground = - new(Windows.UI.Color.FromArgb(255, 28, 24, 18)); + new(Windows.UI.Color.FromArgb(255, 36, 21, 24)); private static readonly SolidColorBrush SlotIdleBrush = new(Windows.UI.Color.FromArgb(255, 30, 40, 48)); @@ -48,6 +48,7 @@ public sealed class SceneDisplayItem public IRelayCommand? DuplicateCommand { get; init; } public string Name => Scene.Name; + public Visibility EditTilesVisibility => Scene.DynamicGallery is not null ? Visibility.Visible : Visibility.Collapsed; public string LayoutLabel => string.IsNullOrWhiteSpace(Scene.Layout) ? "Custom" : Scene.Layout.Replace('-', ' '); @@ -58,17 +59,17 @@ public sealed class SceneDisplayItem public string MetaLabel => $"{LayoutLabel} · {DurationLabel}"; public string StatusLabel => - IsOnProgram ? "PGM" : IsOnPreview ? "PVW" : "IDLE"; + IsOnProgram ? "PROGRAM" : IsOnPreview ? "PREVIEW" : "IDLE"; public Brush StatusBackgroundBrush => IsOnProgram - ? new SolidColorBrush(Windows.UI.Color.FromArgb(255, 240, 168, 92)) + ? new SolidColorBrush(Windows.UI.Color.FromArgb(255, 132, 43, 47)) : IsOnPreview ? new SolidColorBrush(Windows.UI.Color.FromArgb(255, 61, 220, 151)) : new SolidColorBrush(Windows.UI.Color.FromArgb(255, 30, 40, 48)); public Brush StatusForegroundBrush => - IsOnProgram || IsOnPreview + IsOnPreview && !IsOnProgram ? new SolidColorBrush(Windows.UI.Color.FromArgb(255, 8, 14, 12)) : new SolidColorBrush(Windows.UI.Color.FromArgb(255, 184, 200, 192)); diff --git a/native-shell/CoreVideoPro.WinUI/Services/StudioControlSurface.cs b/native-shell/CoreVideoPro.WinUI/Services/StudioControlSurface.cs index 5a0aeeec0..88b2999eb 100644 --- a/native-shell/CoreVideoPro.WinUI/Services/StudioControlSurface.cs +++ b/native-shell/CoreVideoPro.WinUI/Services/StudioControlSurface.cs @@ -63,7 +63,7 @@ public static ControlInvokeResult NdiSetResult(string? refusal) => public static IReadOnlySet SupportedActionIds { get; } = new HashSet(StringComparer.Ordinal) { "zoom.join", "zoom.leave", - "transport.take", "transport.transition.set", + "transport.take", "transport.transition.set", "transport.ftb.toggle", "transport.ftb.set", "transport.record.toggle", "transport.record.set", "transport.stream.toggle", "transport.stream.set", "transport.stream.rtmp.configure", "transport.stream.srt.configure", @@ -87,7 +87,7 @@ public static ControlInvokeResult NdiSetResult(string? refusal) => "audio.mastering.set", "audio.mastering.target", "audio.vst.scan", "multiview.layout.set", "multiview.tileCount.set", "multiview.showLabels.set", "multiview.showTally.set", "multiview.showMeters.set", "multiview.showClock.set", - "automation.magic", "automation.toggle", "automation.autoTake.set", "automation.autoAssignInputs.set", + "automation.autoAssignInputs.set", "automation.lowerThirds.set", "automation.captions.set", "browser.add", "browser.remove", "browser.reload", "settings.programBuffer.set", @@ -251,6 +251,10 @@ private async Task DispatchAsync(string actionId, IReadOnly : ControlInvokeResult.Fail(_vm.Settings.JoinStatus); // ---- Transport ---------------------------------------------------------- + case "transport.ftb.toggle": + return await _vm.SetProgramBlackoutAsync(null); + case "transport.ftb.set": + return await _vm.SetProgramBlackoutAsync(Bool(args, 0)); case "transport.take": return await RunTake(_vm.TakeCommand.CanExecute(null), _vm.TakeForControlAsync).ConfigureAwait(true); case "transport.transition.set": @@ -687,13 +691,9 @@ private async Task DispatchAsync(string actionId, IReadOnly // ---- Automation --------------------------------------------------------- case "automation.magic": - return RunMagicScene(_vm.RunMagicSceneCommand); case "automation.toggle": - _vm.ToggleAutomationCommand.Execute(null); - return ControlInvokeResult.Success; case "automation.autoTake.set": - _vm.AutomationAutoTakeEnabled = Bool(args, 0); - return ControlInvokeResult.Success; + return ControlInvokeResult.Fail(CoreVideoPro.WinUI.ViewModels.MagicScene.MagicSceneCoordinator.SceneAutomationUnavailable); case "automation.autoAssignInputs.set": _vm.AutomationAutoAssignInputsEnabled = Bool(args, 0); return ControlInvokeResult.Success; @@ -990,6 +990,7 @@ public ControlState GetState() Streaming = _vm.Streaming, EngineOn = _vm.ZoomCaptureSubscribed, CanTake = _vm.CanTake, + ProgramBlackout = _vm.ProgramBlackout, // Under instances authority the strip's lower-third chip is the evidence (#1076 C2); // NativeLowerThirdVisible below stays the legacy key's own observation. LowerThirdOnAir = _vm.ManagedLowerThirdAuthority ? _vm.GraphicsLowerThirdOnAir : _vm.ProgramLowerThirdKey.IsVisible, @@ -1221,17 +1222,6 @@ private static async Task RunTransportToggle( return ControlInvokeResult.Success; } - internal static ControlInvokeResult RunMagicScene(System.Windows.Input.ICommand command) - { - if (!command.CanExecute(null)) return ControlInvokeResult.Fail("Magic Scene is unavailable in the current state."); - try - { - command.Execute(null); - return ControlInvokeResult.Success; - } - catch (Exception ex) { return ControlInvokeResult.Fail($"Magic Scene failed: {ex.Message}"); } - } - internal static async Task RunTake(bool canTake, Func> take) { if (!canTake) diff --git a/native-shell/CoreVideoPro.WinUI/Services/StudioWorkspaceLayoutProbe.cs b/native-shell/CoreVideoPro.WinUI/Services/StudioWorkspaceLayoutProbe.cs index aed2c0019..8a4c2db76 100644 --- a/native-shell/CoreVideoPro.WinUI/Services/StudioWorkspaceLayoutProbe.cs +++ b/native-shell/CoreVideoPro.WinUI/Services/StudioWorkspaceLayoutProbe.cs @@ -23,6 +23,11 @@ internal static async Task CheckAsync(Window window, List checks, string try { await using var studio = new StudioViewModel(StudioStartupBootstrap.Create(new InMemoryProductionOutputPreferencesStore(), startInteractiveServices: false)); + studio.TryCreateNamedScene("tiles", "CoreVideo Tiles", out _); + var tilesSceneId = studio.PreviewSceneId; + var originalProgram = studio.ActiveSceneId; + studio.ActiveTab = CoreVideoPro.WinUI.Models.StudioTab.Studio; + studio.ShowGraphicsPanel = false; var page = new StudioWorkspace { ViewModel = studio, RequestedTheme = ElementTheme.Dark }; window.Content = page; window.AppWindow.MoveAndResize(new RectInt32(-20000, -20000, 1920, 1080)); @@ -47,9 +52,10 @@ internal static async Task CheckAsync(Window window, List checks, string if (Math.Min(a.X + automation.ActualWidth, t.X + transport.ActualWidth) - Math.Max(a.X, t.X) > 1 && Math.Min(a.Y + automation.ActualHeight, t.Y + transport.ActualHeight) - Math.Max(a.Y, t.Y) > 1) failures.Add($"{width}x{height}: automation and transport overlap"); - if (width >= 1600 && Math.Abs(a.Y - t.Y) > 1) failures.Add($"{width}x{height}: footer wrapped to two rows (automation y={a.Y:F0}, transport y={t.Y:F0}; footer {footer.ActualWidth:F0}px, automation {automation.DesiredSize.Width:F0}px, transport {transport.DesiredSize.Width:F0}px); owner ruling 2026-11-01 requires one row"); - ((Microsoft.UI.Xaml.Controls.TextBlock)page.FindName("AssignedLookLabel")).Text = "Panel discussion · Quarterly customer leadership summit guest introduction"; - foreach(var name in new[] {"ProgramOutputHealth","StreamOutputHealth","RecordOutputHealth","AutomationStatusText"}) + if (width >= 1600 && Math.Abs(a.Y + automation.ActualHeight - t.Y - transport.ActualHeight) > 1) failures.Add($"{width}x{height}: footer wrapped to two rows (automation y={a.Y:F0}, transport y={t.Y:F0}; footer {footer.ActualWidth:F0}px, automation {automation.DesiredSize.Width:F0}px, transport {transport.DesiredSize.Width:F0}px); owner ruling 2026-11-01 requires one row"); + studio.ProgramBlackoutLabel = "Restoring picture"; + var savedHealth = new[] {"ProgramOutputHealth","StreamOutputHealth","RecordOutputHealth"}.ToDictionary(name => name, name => ((Microsoft.UI.Xaml.Controls.TextBlock)page.FindName(name)).Text); + foreach(var name in new[] {"ProgramOutputHealth","StreamOutputHealth","RecordOutputHealth"}) ((Microsoft.UI.Xaml.Controls.TextBlock)page.FindName(name)).Text="Waiting for destination connection and source readiness"; page.UpdateLayout(); var after=transport.TransformToVisual(page).TransformPoint(new(0,0)); @@ -59,10 +65,10 @@ internal static async Task CheckAsync(Window window, List checks, string var actionRow = (FrameworkElement)page.FindName("FooterOutputActions"); var actionTop = actionRow.TransformToVisual(page).TransformPoint(new(0, 0)).Y; if (Math.Abs(actionRow.ActualHeight - 48) > 1) failures.Add($"{width}x{height}: output actions are not a single 48px row"); - if (Math.Abs(a.Y - t.Y) < 1 && Math.Abs(a.Y - actionTop) > 1) failures.Add($"{width}x{height}: adjacent automation and output action baselines differ"); + if (Math.Abs(a.Y - t.Y) < 1 && Math.Abs(a.Y + automation.ActualHeight - actionTop - 48) > 1) failures.Add($"{width}x{height}: adjacent automation and output action baselines differ"); var telemetry = (FrameworkElement)page.FindName("FooterTelemetry"); var headings = Descendants(telemetry).OfType() - .Where(text => text.Text is "PROGRAM" or "STREAM" or "RECORD" or "FRAME DROPS" or "ELAPSED").ToArray(); + .Where(text => text.Text is "PROGRAM" or "STREAM" or "RECORD" or "DROPPED" or "FEEDS").ToArray(); var headingTops = headings.Select(text => text.TransformToVisual(page).TransformPoint(new(0, 0)).Y).ToArray(); if (headings.Length != 5 || headingTops.Max() - headingTops.Min() > 1) failures.Add($"{width}x{height}: telemetry headings have inconsistent baselines"); if (Descendants(footer).OfType().Any(text => text.Text == "Outputs idle")) failures.Add("Redundant persistent output summary returned"); @@ -77,9 +83,24 @@ internal static async Task CheckAsync(Window window, List checks, string } CheckMultiviewMessagePriority(page, failures, $"{width}x{height}"); checks.Add($"Multiview assignment, preparation, renderer failure and available-picture states are mutually exclusive at {width}x{height}"); + foreach (var entry in savedHealth) ((Microsoft.UI.Xaml.Controls.TextBlock)page.FindName(entry.Key)).Text = entry.Value; + studio.ProgramBlackoutLabel = "Fade to Black"; + studio.Transport.ApplySnapshot(new NativeMediaCoreStateSnapshot(), false, false, "1080p60", false); + await Task.Delay(30); page.UpdateLayout(); await ReviewImageWriter.SaveAsync(page, Path.Combine(directory, $"studio-{width}x{height}.png")); - checks.Add($"Full Studio: {controls.Length} footer actions contained, automation/transport disjoint, long assigned label bounded at {width}x{height}; raster scale {page.XamlRoot.RasterizationScale}; native video pixels excluded"); + checks.Add($"Full Studio: {controls.Length} footer actions contained, automation/transport disjoint, FTB and status labels bounded at {width}x{height}; raster scale {page.XamlRoot.RasterizationScale}; native video pixels excluded"); } + studio.EditTiles(tilesSceneId); + await Task.Delay(150); page.UpdateLayout(); + var tilesPage = Descendants(page).OfType().Single(); + if (studio.PreviewSceneId != tilesSceneId || studio.ActiveSceneId != originalProgram || tilesPage.Workspace?.IsWallSelected != true) + failures.Add("Edit Tiles did not open the selected wall while preserving Program"); + checks.Add("Edit Tiles opens the chosen wall inspector without taking it to Program"); + studio.ActiveTab = CoreVideoPro.WinUI.Models.StudioTab.Studio; + studio.ProgramBlackout = true; studio.ProgramBlackoutLabel = "BLACK · Restore"; + await Task.Delay(30); page.UpdateLayout(); + await ReviewImageWriter.SaveAsync(page, Path.Combine(directory, "studio-ftb-active.png")); + studio.ProgramBlackout = false; studio.ProgramBlackoutLabel = "Fade to Black"; page.Width = 1424; page.Height = 860; foreach (var state in new[] { "preparing", "producing", "interrupted", "failed", "finalizing", "completed", "idle" }) { diff --git a/native-shell/CoreVideoPro.WinUI/ViewModels/MagicScene/MagicSceneCoordinator.cs b/native-shell/CoreVideoPro.WinUI/ViewModels/MagicScene/MagicSceneCoordinator.cs index 9e4c53115..914f4f109 100644 --- a/native-shell/CoreVideoPro.WinUI/ViewModels/MagicScene/MagicSceneCoordinator.cs +++ b/native-shell/CoreVideoPro.WinUI/ViewModels/MagicScene/MagicSceneCoordinator.cs @@ -21,6 +21,11 @@ namespace CoreVideoPro.WinUI.ViewModels.MagicScene; public sealed partial class MagicSceneCoordinator : ObservableObject { private readonly IMagicSceneHost _host; + // First-release scope: only isolated characterization tests can opt in. + // No settings, environment variable, license or control command enables this. + private readonly bool _sceneAutomationAvailable; + public const string SceneAutomationUnavailable = + "Scene automation is unavailable in this release. Use CoreVideo Tiles and manual Take."; private readonly IAutomationTimer _timer; private readonly Func _clock; private readonly DirectorBindingHoldPolicy _bindingHold = new(); @@ -95,8 +100,16 @@ public bool AutomationCaptionsEnabled ProductionStateHelper.BuildAutomationRecommendation([], ProductionCatalog.Scenes); public MagicSceneCoordinator(IMagicSceneHost host, Func? clock = null) + : this(host, clock, sceneAutomationAvailable: false) + { + } + + internal MagicSceneCoordinator(IMagicSceneHost host, Func? clock, bool sceneAutomationAvailable) { _host = host; + _sceneAutomationAvailable = sceneAutomationAvailable; + _automationAutoTakeEnabled = sceneAutomationAvailable; + _automationLowerThirdsEnabled = sceneAutomationAvailable; var start = System.Diagnostics.Stopwatch.GetTimestamp(); _clock = clock ?? (() => DateTimeOffset.UnixEpoch + System.Diagnostics.Stopwatch.GetElapsedTime(start)); _timer = host.CreateAutomationTimer(EvaluateAutomationPolicy); @@ -153,6 +166,7 @@ private void CuePreview(string sceneId) [RelayCommand] private void ToggleAutomation() { + if (!_sceneAutomationAvailable) { DisableSceneAutomation(); return; } ProductionMode = ProductionMode == ProductionMode.SetAndForget ? ProductionMode.Manual : ProductionMode.SetAndForget; @@ -169,6 +183,7 @@ private void ToggleAutomation() [RelayCommand] private void RunMagicScene() { + if (!_sceneAutomationAvailable) { DisableSceneAutomation(); return; } _host.RefreshAutomationRecommendation(); if (!_host.IsInMeeting) { @@ -214,6 +229,7 @@ public void EvaluateAutomationPolicy() private void EvaluateAutomationPolicyCore() { + if (!_sceneAutomationAvailable) { DisableSceneAutomation(reportCommand: false); return; } _host.RefreshAutomationRecommendation(); ObserveAutomationSession(); if (ProductionMode != ProductionMode.SetAndForget) @@ -459,6 +475,11 @@ public string BuildAutoProductionReadout() partial void OnProductionModeChanged(ProductionMode value) { + if (!_sceneAutomationAvailable && value != ProductionMode.Manual) + { + DisableSceneAutomation(); + return; + } _modeGeneration++; if (value != ProductionMode.SetAndForget) _timer.Stop(); _pendingSceneId = null; @@ -475,7 +496,11 @@ partial void OnProductionModeChanged(ProductionMode value) OnPropertyChanged(nameof(AutoProductionReadout)); } - partial void OnAutomationAutoTakeEnabledChanged(bool value) => OnAutomationPolicyChanged(); + partial void OnAutomationAutoTakeEnabledChanged(bool value) + { + if (!_sceneAutomationAvailable && value) { AutomationAutoTakeEnabled = false; return; } + OnAutomationPolicyChanged(); + } partial void OnAutomationPreferScreenShareChanged(bool value) => OnAutomationPolicyChanged(); @@ -533,6 +558,19 @@ private void ResetPendingCandidate() _bindingHold.Reset(); } + private void DisableSceneAutomation(bool reportCommand = true) + { + _timer.Stop(); + ResetPendingCandidate(); + _lastTakenBindings = null; + ProductionMode = ProductionMode.Manual; + AutomationAutoTakeEnabled = false; + AutomationLastAction = SceneAutomationUnavailable; + MagicSceneStatus = SceneAutomationUnavailable; + if (reportCommand) _host.CommandStatus = SceneAutomationUnavailable; + RefreshTransportAutomationState(); + } + private void ObserveAutomationSession() { var current = (_host.CoreEpoch, _host.RosterEpoch, _host.IsMediaCoreRunning, _host.IsInMeeting); diff --git a/native-shell/CoreVideoPro.WinUI/ViewModels/SceneWorkspaceViewModel.cs b/native-shell/CoreVideoPro.WinUI/ViewModels/SceneWorkspaceViewModel.cs index 70fa00692..cb341e910 100644 --- a/native-shell/CoreVideoPro.WinUI/ViewModels/SceneWorkspaceViewModel.cs +++ b/native-shell/CoreVideoPro.WinUI/ViewModels/SceneWorkspaceViewModel.cs @@ -95,6 +95,7 @@ private void OnStudioChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(StudioViewModel.PreviewSceneId)) { _sceneId = _studio.PreviewSceneId;_resetSavedFingerprint=true; _undo.Clear();_redo.Clear();_initialRects.Clear();Selected=null;UpdateHistory(); } + if (e.PropertyName == nameof(StudioViewModel.PendingTilesEditorSceneId)) Refresh(); if (e.PropertyName is nameof(StudioViewModel.PreviewCanvasLayers) or nameof(StudioViewModel.PreviewSceneId)) Refresh(); if(e.PropertyName is nameof(StudioViewModel.GalleryMembershipSummary) or nameof(StudioViewModel.GalleryMemberChoices)) RefreshMembers(); if(e.PropertyName==nameof(StudioViewModel.ActiveSceneId))OnPropertyChanged(nameof(PreviewBadge)); @@ -109,6 +110,11 @@ public void Refresh() for (var i=0;il.ItemId==selection) ?? Items.FirstOrDefault(); + if (_studio.PendingTilesEditorSceneId == _studio.PreviewSceneId) + { + Selected = Items.FirstOrDefault(l => l.IsTilesWall) ?? Selected; + _studio.PendingTilesEditorSceneId = null; + } OnSelectedChanged(Selected);AddTilesCommand.NotifyCanExecuteChanged(); OnPropertyChanged(nameof(TransparentBackground)); RefreshMembers(); diff --git a/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.GraphicsMode.cs b/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.GraphicsMode.cs index 7301e04c3..a4744c8b4 100644 --- a/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.GraphicsMode.cs +++ b/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.GraphicsMode.cs @@ -38,7 +38,7 @@ private bool ApplyGraphicsMode(string? value) } /// The compact playlist column in the Studio tab (spec: right panel of the console). - [ObservableProperty] private bool _showGraphicsPanel = true; + [ObservableProperty] private bool _showGraphicsPanel; /// Design mode shows the template-first builder by default; the old workspace /// (show templates, saved cues and styles, packages, automation) sits behind "Cues & automation". diff --git a/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.ProgramBlackout.cs b/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.ProgramBlackout.cs new file mode 100644 index 000000000..8f847f5a1 --- /dev/null +++ b/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.ProgramBlackout.cs @@ -0,0 +1,72 @@ +using System.Text.Json; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using CoreVideoPro.Control; +using CoreVideoPro.MediaCore.Models; + +namespace CoreVideoPro.WinUI.ViewModels; + +public sealed partial class StudioViewModel +{ + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(ProgramBlackoutBrush))] + private bool _programBlackout; + public Microsoft.UI.Xaml.Media.SolidColorBrush ProgramBlackoutBrush => new(ProgramBlackout + ? Windows.UI.Color.FromArgb(255, 240, 82, 82) : Windows.UI.Color.FromArgb(255, 65, 72, 78)); + [ObservableProperty] private string _programBlackoutLabel = "Fade to Black"; + private bool _blackoutInFlight; + + private void ApplyProgramBlackoutSnapshot(NativeMediaCoreStateSnapshot snapshot) + { + ProgramBlackout = snapshot.ProgramBlackout == true; + ProgramBlackoutLabel = snapshot.ProgramBlackout switch + { + true when snapshot.ProgramBlackoutOpacity < .999 => "Fading to black", + true => "BLACK · Restore", + false when snapshot.ProgramBlackoutOpacity > .001 => "Restoring picture", + _ => "Fade to Black" + }; + } + + [RelayCommand] + private async Task ToggleProgramBlackout() + { + var result = await SetProgramBlackoutAsync(null); + if (!result.Ok) CommandStatus = result.Error ?? "FTB unavailable"; + } + + // All callers share admission and native observation, including remote set/toggle. + public async Task SetProgramBlackoutAsync(bool? enabled) + { + if (_blackoutInFlight) return ControlInvokeResult.Fail("FTB command is already in progress."); + if (!_bridge.Running) return ControlInvokeResult.Fail("FTB unavailable: media core is offline."); + _blackoutInFlight = true; + try + { + var before = await _bridge.PollSnapshotAsync(); + if (before.ProgramBlackout is not bool current) + return ControlInvokeResult.Fail("This media core does not support Fade to Black."); + var target = enabled ?? !current; + var snapshot = await _bridge.SyncAsync([new NativeMediaCoreCommand + { + Type = "program-blackout", + ExtensionData = new() + { + ["enabled"] = JsonSerializer.SerializeToElement(target), + ["durationMs"] = JsonSerializer.SerializeToElement(300) + } + }]); + ApplyProgramBlackoutSnapshot(snapshot); + if (snapshot.ProgramBlackout != target) + return ControlInvokeResult.Fail("Media core did not acknowledge FTB."); + CommandStatus = target ? "Fading Program to black — audio continues" : "Restoring Program picture"; + return ControlInvokeResult.Success; + } + catch (Exception ex) + { + CommandStatus = $"FTB unavailable: {ex.Message}"; + return ControlInvokeResult.Fail(CommandStatus); + } + finally { _blackoutInFlight = false; } + } +} diff --git a/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.TilesNavigation.cs b/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.TilesNavigation.cs new file mode 100644 index 000000000..f5d484e7d --- /dev/null +++ b/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.TilesNavigation.cs @@ -0,0 +1,16 @@ +using CoreVideoPro.WinUI.Models; +namespace CoreVideoPro.WinUI.ViewModels; +public sealed partial class StudioViewModel +{ + public string? PendingTilesEditorSceneId { get; set; } + public void EditTiles(string sceneId) + { + if (!Scenes.Any(scene => scene.Id == sceneId && scene.DynamicGallery is not null)) return; + SelectSceneCommand.Execute(sceneId); + if (PreviewSceneId != sceneId) return; + PendingTilesEditorSceneId = sceneId; + ActiveTab = StudioTab.Sources; + OnPropertyChanged(nameof(PendingTilesEditorSceneId)); + CommandStatus = $"Editing Tiles in {PreviewScene.Name}"; + } +} diff --git a/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.cs b/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.cs index fe0f8bcbd..b03dfafc6 100644 --- a/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.cs +++ b/native-shell/CoreVideoPro.WinUI/ViewModels/StudioViewModel.cs @@ -2099,11 +2099,11 @@ private async void RunNdiOutputSync(string reason) public Brush RecordButtonBackground => Recording ? new SolidColorBrush(Windows.UI.Color.FromArgb(255, 229, 72, 77)) - : new SolidColorBrush(Windows.UI.Color.FromArgb(255, 74, 32, 32)); + : new SolidColorBrush(Windows.UI.Color.FromArgb(255, 32, 38, 40)); public Brush RecordButtonBorder => Recording ? new SolidColorBrush(Windows.UI.Color.FromArgb(255, 229, 72, 77)) - : new SolidColorBrush(Windows.UI.Color.FromArgb(255, 224, 90, 90)); + : new SolidColorBrush(Windows.UI.Color.FromArgb(255, 43, 51, 55)); public Brush RecordButtonForeground => Recording ? new SolidColorBrush(Windows.UI.Color.FromArgb(255, 255, 248, 248)) @@ -2111,11 +2111,11 @@ private async void RunNdiOutputSync(string reason) public Brush StreamButtonBackground => Streaming ? new SolidColorBrush(Windows.UI.Color.FromArgb(255, 61, 220, 151)) - : new SolidColorBrush(Windows.UI.Color.FromArgb(255, 30, 48, 64)); + : new SolidColorBrush(Windows.UI.Color.FromArgb(255, 32, 38, 40)); public Brush StreamButtonBorder => Streaming ? new SolidColorBrush(Windows.UI.Color.FromArgb(255, 61, 220, 151)) - : new SolidColorBrush(Windows.UI.Color.FromArgb(255, 90, 159, 212)); + : new SolidColorBrush(Windows.UI.Color.FromArgb(255, 43, 51, 55)); public Brush StreamButtonForeground => Streaming ? new SolidColorBrush(Windows.UI.Color.FromArgb(255, 7, 17, 14)) @@ -10578,6 +10578,7 @@ void LogIfSlow(string exit) // The compositor is always on, so surfaces always accept the latest program frame. _surfaces.OnMediaCoreSnapshot(snapshot); + ApplyProgramBlackoutSnapshot(snapshot); ApplyRtmpIngestSnapshot(snapshot); Tm("surfaces"); diff --git a/native-shell/CoreVideoPro.WinUI/Views/AutomationPage.xaml b/native-shell/CoreVideoPro.WinUI/Views/AutomationPage.xaml index 4f3e4fec3..ec56fc5f8 100644 --- a/native-shell/CoreVideoPro.WinUI/Views/AutomationPage.xaml +++ b/native-shell/CoreVideoPro.WinUI/Views/AutomationPage.xaml @@ -2,195 +2,11 @@ x:Class="CoreVideoPro.WinUI.Views.AutomationPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> - - - - - - - - - - - - - - - - - - - - - - - -