fix(alerts): silent decoder falls back to the six animations after a 1s no-frame grace
Routing and ruling both good: 'procs in the chat windows but nothing in the alert box'
with zero exceptions — every failure stage was silent by design (Debug.WriteLine-only
preview catch, bare catch{} in RunAsync firing Completed regardless). A decode run that
starts but yields neither a frame nor an audio chunk left _clip != null with
_latestClipFrame == null, so RenderClipFrame returned null forever: the box stayed
transparent for the whole alert and the six-animation fallback (which only ran on
setup-time throws) never fired.
Fix: AlertOverlayLayer.Advance gives a started clip a NoFrameFallbackSeconds (1.0s)
grace — produce no frame AND no audio inside it and the clip is torn down, _elapsed
resets, and the SAME alert continues as the animation branch (never blank, never drained
early). Diagnostics stop the lying silence: BeginClip logs box id/path/size + setup
failures; AlertClipDecoder.RunAsync logs frame/chunk end-state and the exception it used
to swallow.
Good Dog test: SilentDecoder_FallsBackToTheAnimationAfterTheNoFrameGrace (transparent
inside grace, disposed past it, animation renders, drains to idle).
Reference: alert playback must degrade to its fallback on dead-air, never vanish —
same contract as every player/booth failure budget (e.g. OBS source fallbacks).
https://obsproject.com/forum/threads/source-visibility-fallback.187383/
This commit is contained in:
@@ -881,3 +881,30 @@ Red pre-fix (it was the poller's), green post-fix.
|
||||
|
||||
Grep-ahead: a `DispatcherTimer` ctor guarded by `if (Application.Current != null)` marks a class
|
||||
with UI-thread affinity — audit every production ingress point for the marshal when adding one.
|
||||
|
||||
---
|
||||
|
||||
## A decoder that "starts" but yields nothing is DEAD AIR — fall back on a no-frame grace, never trust silent catches (2026-09-26)
|
||||
|
||||
Second live alert failure of the day, a different void than the crash: creator's repro — On-Air →
|
||||
test → remove and re-add the Stream Alerts layer → TEST event → procs in chat but the alert box
|
||||
stayed transparent, and startup.log 11:44's `peakMix 0.105` proved the alert audio never reached the
|
||||
mix (vs 11:21's 0.375–0.891). ZERO exceptions anywhere; every failure stage was silent BY DESIGN:
|
||||
`UpdatePreview`'s catch was `Debug.WriteLine`-only (nothing in release), and `AlertClipDecoder.RunAsync`
|
||||
had a bare `catch { }` around the whole run (fires `Completed` regardless). A decode run that fails
|
||||
AFTER `BeginClip` succeeds leaves `_clip != null` with `_latestClipFrame == null` → `RenderClipFrame`
|
||||
returns null forever → box transparent FOREVER, and the six-animation fallback only ever ran on
|
||||
setup-time throws. Even frame pacing was silently off (no frame-rate probe → `frameDuration = 0` →
|
||||
video dumps instantly while 50 ms audio chunks pace the whole clip).
|
||||
|
||||
The established answer (derivative: any video-player/booth failure budget has the same contract):
|
||||
**an alert that plays is a promise — the moment data stops arriving, degrade, don't vanish.** Fixed
|
||||
in `AlertOverlayLayer.Advance`: a started clip that produced neither a video frame NOR an audio chunk
|
||||
inside a `NoFrameFallbackSeconds` (1.0 s) grace is torn down, `_elapsed` resets to 0, and the SAME
|
||||
alert continues as the six-animation branch — never drained early, never blank. And the silence is
|
||||
gone: `BeginClip` writes the box id / resolved path / size + setup failure; `RunAsync` now logs the
|
||||
frame/chunk end-state AND the exception it swallowed. Rules for every future gamble:
|
||||
(1) a `catch` that hides WHY the output vanished is a lie — log the exception and the counters;
|
||||
(2) any producer that yields zero output inside a grace becomes a fallback trigger, not a wait;
|
||||
(3) one integration test per rescue: `SilentDecoder_FallsBackToTheAnimationAfterTheNoFrameGrace`
|
||||
pins transparent→fell-back→renders→drains.
|
||||
|
||||
Reference in New Issue
Block a user