Files
LlamaCasty/HANDOFF.md
T
gramps 76f51e6f4e fix: FramePump paces one frame per deadline slot — duplicate-on-lag, never skip (slice 15)
ty-1723/1726 device takes showed accelerated playback + audio tail cut-off:
a render overrun (~35ms vs the 16.6ms slot) SKIPPED the missed slots (slice 10's
freshness choice), so a 60fps-authoring pump wrote one frame per 35ms into a
60fps container — 1723: 697 frames/11.62s vs 11.84s audio; 1726: 163/2.72s vs
2.93s, video ending 0.21-0.24s early.

OBS never leaves a wall-time hole: the video thread emits one frame per tick and
a lagging producer DUPLICATES the newest frame ("lagged frames due to rendering
lag/stalls" — obs-output.c; "If the video frame queue is full, it will duplicate
the last frame" — docs.obsproject.com/backend-design). The pump's submit is now a
bounded catch-up over the missed slots (while now >= nextTick), fresh on the first,
repeated after — duration == wall, judder not fast-forward. Safe because Channel.
TryWrite never blocks (the take-9 smear was the blocking pipe-write; each emit is
nanoseconds). Burned frame index moved inside the loop: every emitted slot carries
its own +1 (also fixes the old unconditional pre-gate bump that gapped the judge
sequence on non-submitting fast-render iterations).

Good Dog test: Pump_Overrun_Renders_EmitsEverySlot_NotSkipped (60fps, 35ms render
cost, asserts >=0.65 of the wall slots emitted). 294/294 green, 0 warnings.

No push — web/A/V work is commit-local until greenlight.
2026-09-14 17:40:59 -07:00

91 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# HANDOFF — 2026-09-14 (composition capture DEVICE-VERIFIED ✓; slice-15 pacing fix committed locally — A/V re-measure next)
## Branch / Commit State
`main` HEAD = **slice-15 commit** (FramePump duplicate-on-lag pacing — committed LOCALLY, **NOT
pushed**; web/A/V work stays commit-local until greenlight). Before it: `c01206f` (composition
capture redesign, also local/unpushed), before that `b22d08e` (signed audio-sync, pushed).
Working tree **clean**.
## ⚠️ Branding (2026-09-14, creator-corrected): product = **llamacasty**, internals = ytLive
The product is **llamacasty**; repo path, csproj `AssemblyName`/`RootNamespace`, DB/log paths
(`%APPDATA%\ytLlive\...`), and most code names are the legacy **ytLive/ytLlive**. User-facing
language says "llamacasty"; code/assembly/repo names stay ytLive. See `ai.md` → Brand.
## ✅ DEVICE-VERIFIED — composition capture looks good; then the A/V defect surfaced
The creator ran real takes off the `c01206f` build and reports the video looks **very good** — the
Windows.Graphics.Capture web path is confirmed on device (open item closed). BUT the same takes
showed the A/V defect we have seen before: **both desktop and webcam playback are accelerated, the
audio "gets speedier", then cuts off at the end.**
## 🔬 Sliced and measured (evidence)
With the A/V recipe (`MyMistakes.md` → "Measuring audio-video A/V sync" + `/tmp/opencode/avsync.py`):
- `ty-20260914-1723-0000-2.mp4`: 697 video frames @60fps = **11.62s** vs audio **11.84s**.
- `ty-20260914-1726-0000-2.mp4` (clap take): 163 frames = **2.72s** vs **2.93s** audio. Video ends
0.21–0.24s before audio → the cut-off. Clap: audio env peak 1.655s vs video motion 0.75–1.03s;
cross-correlation lag **+0.667s** (audio late).
- `startup.log`: `FramePump stall: iteration 33-46ms (> 2× the 17ms interval): worst render 33ms …
dropped 0`.
**Root cause (slice 15):** slice 10's freshness choice skipped the overrun's missed slots — one
fresh frame per ~35ms stall authored into a 60fps container = **accelerated playback**. OBS's
answer is duplicate-on-lag (`libobs/video-io.c`, docs.obsproject.com/backend-design): fill each
missed slot by repeating the newest frame — duration == wall, judder never fast-forward.
## 🔬 Committed locally — slice 15: one frame per deadline slot (duplicate-on-lag)
**What:** `Services/Encoder/FramePump.cs` submit is now a bounded catch-up —
`while (now >= nextTick) { submit latest composite; nextTick += intervalTicks; }` clamped to a
`deadlineNow` captured once per iteration. First missed slot gets the fresh composite, the rest get
repeats of it (OBS duplication) — recording duration == wall time under any render load, no
acceleration, no audio tail cut. The burned `_outputIndex` moved inside the submit loop (every
emitted slot gets its own +1; also fixes the old unconditional bump that gapped the judge sequence
on non-submitting fast-render iterations).
**Good Dog test:** `ytLive.Tests/FramePumpTests.cs` → `Pump_Overrun_Renders_EmitsEverySlot_NotSkipped`
(60fps, 35ms render cost, asserts ≥0.65 of the wall slots emitted — the old skip-pump wrote ~1/35ms).
**294/294 green, app build 0 warnings.** Files: `Services/Encoder/FramePump.cs`,
`ytLive.Tests/FramePumpTests.cs`. Docs in same commit: ai.md Slice 15, MyMistakes (supersedes the
slice-10 "no burst re-write" clause + latest numbers), this HANDOFF.
## ⚠️ Open items (before PUSHABLE)
- **Device re-verify:** a take on the slice-15 build must play at REAL time (no acceleration, no
cut-off audio tail). Confirm via ffprobe: video stream duration ≈ audio ≈ container.
- **Re-measure the true A/V offset** with a clap take now that video pacing is honest
(`/tmp/opencode/avsync.py`). The +0.6s reading on 1726 was confounded by the 1.1x
acceleration. If a real residual remains after the pacing fix, the backlog is the AUDIO pipeline
(mixer ring / advance), not video.
- **No push yet** — commit-locally-until-greenlight for web/A/V work.
## Open threads (carried)
- Audio-silence verification — fixed (`724af14`); creator heard real audio.
- Webcam MJPG missing / ~10–14Hz, layer SortOrder, truncation-with-dynamic-scenes — queued.
- Sync control user-doc tutorial — REQUIRED before 1.0 (creator directive; TASK 22).
- Signed A/V sync: verify the negative (advance) direction on device.
## Landmines
- testhost shares startup.log — filter by time.
- `cmd.exe /c "taskkill /F /IM ytLive.exe"` (WSL double-slashes mangle) before rebuilds — a live
app process locks `ytLive.exe` and the apphost copy fails (MSB3021, seen today).
- Build/tests: **Windows dotnet host** (`/mnt/c/Program Files/dotnet/dotnet.exe`). 0 warnings —
only `./scripts/verify.sh "<files>"`'s clean build counts. Building `ytLive.csproj` alone does
NOT rebuild `ytLive.Tests.dll` — run the Tests csproj before `vstest`.
- ffmpeg/ffprobe: `/mnt/c/Program Files/Krita (x64)/bin/` with Windows paths.
- `MyMistakes.md` has the **A/V sync measurement recipe**, the **deadline-pacing** lessons
(item 1 + slice 15), and the **CoreMessaging DQ recipe** — grep before re-deriving.
- sqlite3 at `/home/gramps/android-sdk/platform-tools/sqlite3` for
`/mnt/c/Users/gramp/AppData/Roaming/ytLlive/ytLlive.db`.
## Next step
Have the creator record a clap take on the slice-15 build → ffprobe durations (video == audio ==
wall) + `/tmp/opencode/avsync.py` for the honest offset. If durations match, the acceleration
defect is closed; then decide push with the user, and attack any true audio-latency residual as its
own work unit.