Files
LlamaCasty/HANDOFF.md
T

88 lines
5.4 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 (signed audio sync SHIPPED + PUSHED: −500..+500, negative advances by eating the stream head; slider locked while live/recording)
## Branch / Commit State
`main` HEAD = **`b22d08e`** (signed audio-sync, committed AND **pushed** to origin/main with the
user's greenlight — 29 commits pushed in one go). Working tree **clean**.
DB now: **`Audio.SyncOffsetMs = 0`** (confirmed via sqlite3 — the creator slid the sync to 0
and the write finally stuck; sound is correct at 0). The 0.54s residual in the 1128 take ≈ 300ms
injected offset (leftover DB value) + ~240ms natural (partly webcam clap-quantization ±40–85ms,
partly measurement).
## ⚠️ Branding (2026-09-14, creator-corrected): product = **llamacasty**, internals = ytLive
The product is **llamacasty**; the repo path, csproj `AssemblyName`/`RootNamespace`, DB/log paths
(`%APPDATA%\ytLlive\...`), and most code names are the legacy **ytLive/ytLlive**. User-facing
language must say "llamacasty"; code/assembly/repo names stay ytLive. Full detail in
`ai.md` → Brand → "Product name vs repo/assembly branding".
## ✅ SHIPPED (this dirty tree) — signed audio sync, −500..+500
**What:** the audio-sync control is now a SIGNED offset. Positive = delay the mix (audio runs
AHEAD of video — existing `AudioSyncDelay` behavior, unchanged and live-reactive). Negative =
**advance** the audio (audio runs BEHIND video): OBS's "eat the head of the buffer" fix —
the mixer drops the first |N| ms of the written stream at the pipe, re-anchoring the audio
stream so every event lands |N| ms EARLIER relative to video.
**Mechanism (AudioMixer):** `StartLive` arms `_advanceSamplesRemaining = |N| ms → samples` at
go-live (a negative offset can only eat the HEAD of the stream; it is armed once, not
live-reactive). `LiveLoopAsync` skips `min(budget, mixBuffer.Length)` samples off each write
head while the budget lasts — the pipe writer accepts a partial chunk via `AsMemory(writeFrom)`.
Positive path untouched (delay line still re-reads the Func every tick).
**UI/plumbing:**
- `MainViewModel.Audio.cs` — clamp `Math.Clamp(value, -500, 500)`, doc updated.
- `LayoutStore.Settings.cs` — `LoadAudioSyncOffsetMs`/`SaveAudioSyncOffsetMs` clamp −500..500.
- `PreviewPane.xaml` — label **SYNC → "AUDIO SYNC"**, `Minimum="-500"`, tooltip explains both
directions (calibrate with a clap: clap late → negative; early → positive), and
**`IsEnabled="{Binding IsEditMode}"`** — the slider locks during live AND recording (gun
safety, same property `IsRecording`/`StreamStatus` already raise PropertyChanged for).
- `AudioSyncDelay` unchanged (still clamps negative→0 internally; header doc updated to point
at the mixer for the advance side).
**Regression test (the ONE integration test for this change):**
`StartLive_NegativeOffset_AdvancesAudio_ByDroppingTheStreamHead` in `AudioPipelineTests.cs` —
−40 ms advance (8-tick budget at 5ms interval), emits 6×0.9 fresh right after StartLive (≤
budget, so the head MUST be eaten) then a long 0.2 bed; asserts the wire max ≈ 0.2 (< 0.3).
Fails loudly if −N no longer drops the head (0.9 leaks).
**User directives (this session):**
- Signed −500..+500 with positive=delay / negative=advance, relabel "AUDIO SYNC", default 0.
- **Lock the sync control when live or recording** (done — `IsEditMode`).
- **NOTE ONLY, no fix:** the live recording is completely different from the "recording
results" shown in Chat view (recorded in `bugs.md` — do not rediscover as a surprise).
- **Before 1.0:** write a detailed USER-DOC tutorial on the audio-sync feature (see TASKS.md
note; add it to the gold-pass/1.0 checklist). `docs/` currently holds only the README image.
## Take verification so far (ring-backlog fix)
Take `ty-20260914-1128-0000-2.mp4` (1920×1080@60fps, 356 frames / 5.93s): audio clap RMS peak
3.260s; video diff-frame 163 → 2.717s; **offset ≈ +0.54s** — collapsed from +2.11/2.22s; the
remaining ~300ms was the baked-in `SyncOffsetMs=300` (now 0). Both streams `start_time=0` — not
an `avoid_negative_ts` artifact.
## Open threads
- **Verify signed sync on device:** re-run the clap take with a NEGATIVE offset to confirm the
advance direction end-to-end (the regression test proves the mixer; a take proves the file).
- **Audio-silence verification** — fixed code (`724af14`) confirmed; creator heard real audio.
- **Webcam MJPG missing / ~10–14Hz**, layer SortOrder, truncation-with-dynamic-scenes — queued.
- **Sync control tutorial in user docs — REQUIRED before 1.0** (creator directive).
## Landmines
- testhost shares startup.log — filter by time.
- `cmd.exe /c "taskkill /F /IM ytLive.exe"` (WSL double-slashes mangle) before rebuilds.
- Build/tests: **Windows dotnet host** (`/mnt/c/Program Files/dotnet/dotnet.exe`). 0 warnings.
- ffmpeg/ffprobe: `/mnt/c/Program Files/Krita (x64)/bin/` with Windows paths.
- `MyMistakes.md` has the **audio/video sync measurement recipe** (claps + cross-correlation)
— grep it before re-deriving.
- sqlite3 lives at `/home/gramps/android-sdk/platform-tools/sqlite3` (WSL) for the DB at
`/mnt/c/Users/gramp/AppData/Roaming/ytLlive/ytLlive.db`.
## Next step
Open queue question: user-doc tutorial for the audio-sync feature (creator directive, REQUIRED
before 1.0 — recorded in `TASKS/task-22-audio-sync-offset.md`). Also asked 2026-09-14 whether
other root md files need the TASKS-style split — answered: no (see below for the criterion).