5.4 KiB
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— clampMath.Clamp(value, -500, 500), doc updated.LayoutStore.Settings.cs—LoadAudioSyncOffsetMs/SaveAudioSyncOffsetMsclamp −500..500.PreviewPane.xaml— label SYNC → "AUDIO SYNC",Minimum="-500", tooltip explains both directions (calibrate with a clap: clap late → negative; early → positive), andIsEnabled="{Binding IsEditMode}"— the slider locks during live AND recording (gun safety, same propertyIsRecording/StreamStatusalready raise PropertyChanged for).AudioSyncDelayunchanged (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.mdhas 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). Pre-flight item to confirm next
session: creator wanted to discuss whether other root-level md files (beyond TASKS.md) should
be split one-topic-per-file like TASKS/.