Reported 2026-11-06: a Release instance crashed when clicking Go Live in test mode, while a Debug
instance was recording its window. The Windows event log gave the cause:
System.IO.IOException: All pipe instances are busy.
at System.IO.Pipes.NamedPipeServerStream.Create(...)
at ytLive.Services.Audio.NamedPipeAudioWriter.Start(...)
at ytLive.Services.Audio.AudioMixer.StartLive(...)
at MainViewModel.StartStreamingSession(...)
at MainViewModel.BeginTestStream(...)
at MainViewModel.StartFromPrimaryButton(...)
at System.Windows.Controls.Button.OnClick()
Two defects, both fixed:
1. **A button click could end the process.** `StartLive` throws when the pipe name is taken, and nothing
on the go-live path caught it. `TryStartAudioPipe` now catches, logs, toasts ("Another copy of
LlamaCasty is already using the audio pipe") and rolls the session back. Recording-only takes the same
path.
2. **The pipe name was a shared constant**, so a second instance could never go live on the same machine.
`InstanceProfile.AudioPipeName` appends the dev instance id (DEBUG only); Release keeps the plain name
so the normal single-instance case is unchanged. The encoder reads the same derived name, so mixer and
ffmpeg cannot disagree.
Tests: `AudioPipeInstanceTests` — a second server on one name throws (the collision is real), dev names
derive per instance, and a writer on a taken name throws rather than silently reusing the pipe.
Debug and Release both build clean.
3.0 KiB
HANDOFF — 2026-11-05 (alert stack + media/chroma fixes)
State
main. TASK 21 (video layer + soundtrack), TASK 64 (green/blue screen) and TASK 32·4 (fragmented MP4) are complete; TASK 49 is retired (YouTube owns chat moderation — we just don't paint tombstones).- Left panel alert stack shipped: Steam licence indicator pinned at row 1 (
Entitlement 30 fps · Maximum 60 fps, pin → close once owned, permanent while owned), event rows LIFO beneath, click → About or the Logs tab with that event's lines painted. Detail:docs/ai/ui-surface.md. - Video layer fixes this session: the preview-pane trigger whitelist (a video layer was invisible), a quadratic frame copy that capped 1080p playback at 2 fps, and deadline pacing for video and audio.
- Tests: 575 green, 1m50s;
FAST=1 ./scripts/verify.sh= 527 in ~62s.
Next action
-
32·1 + 32·2 shipped: blip retry (immediate/+1/+2/+3 s), and the RECONNECTING sign driven by the status poll (4 s cadence while recovering) with measured elapsed/attempt only — the countdown was dropped after the creator pointed out YouTube's cutoff depends on variables we cannot see. The
chatEndedEventin the chat feed now prompts an immediate status check. -
32·5 shipped: ingest pre-flight (TCP, 2 s) aborts go-live before any API call, so a dead network leaves no ghost broadcast.
-
Next: then 32·2/32·3 (countdown + Back on air) which need YOUR measurement take: pull the network on a private stream and time how long YouTube holds the broadcast.
-
Open loop:
32·4is proven by construction only — kill ffmpeg mid-recording and play the file. -
Do not push absent a checkpoint request.
-
Steam is a wait, not a task: partner account exists, identity verification pending, tax review in Valve's queue (up to 30 business days). No app IDs, no store page, Release entitlement still fails closed. Earliest realistic launch early-to-mid February 2027 — see
Distribution.md§2.
Landmines
- The preview pane draws frame-source layers from a whitelist of DataTriggers. A layer type with no
trigger is invisible in the preview while its decode looks healthy (alert box 2026-09-26, scoreboard,
video layer 2026-11-05). Add the trigger with the layer type; pin it with
MediaPreviewDisplayTests. - Nothing in the suite drives the real cursor any more; the drag arithmetic is pure (
DragReorderMathTests). - Integration tests constructing
MainWindowmust set a temporaryLayoutPathOverrideand clear it infinally. - Media sessions are keyed by path + look (
MainViewModel.MediaSessionKey); never acquire by raw path. - The audio pipe is one instance per machine.
NamedPipeAudioWriterallows a single server, so two LlamaCasty processes cannot both go live. A DEBUG instance appends its id (InstanceProfile.AudioPipeName), Release keeps the plain name; the Go-Live path catches the failure and reports instead of dying. - Bundled FFmpeg stays outside the single-file exe (
ExcludeFromSingleFile="true").