diff --git a/services/capture/deltacast-bridge/main.c b/services/capture/deltacast-bridge/main.c index 9c12c54..c184c50 100644 --- a/services/capture/deltacast-bridge/main.c +++ b/services/capture/deltacast-bridge/main.c @@ -276,6 +276,42 @@ static void *audio_thread(void *arg) { } fcntl(fd, F_SETPIPE_SZ, 1024 * 1024); + /* ── Flush the VHD audio slot backlog to the LIVE edge ────────────── + * While no reader is attached (recorder idle/standby), the open() above + * blocks but the VHD audio stream keeps running, so its internal slot + * queue fills with buffered audio. Without flushing, the first thing a + * newly-attached reader (the record ffmpeg) receives is that backlog — + * several seconds of stale/sync-warmup audio that plays as leading + * silence and pushes the audio stream out of alignment with the live + * video. Drain all immediately-available slots (non-blocking via the + * SDK timeout) so we hand the reader the LIVE edge, frame-aligned with + * the video that fc_pipe is delivering right now. */ + if (have_vhd_audio) { + /* Drain the QUEUED backlog only: keep discarding slots while each + * lock returns FAST (the board hands back already-buffered slots in + * well under a frame period). The first lock that takes ~a full frame + * period means the queue is empty and we're now waiting on a LIVE + * slot — at that point we've reached the live edge, so stop WITHOUT + * consuming it (the inner loop will pick it up and write it). */ + const long fast_ns = frame_ns / 2; /* "immediate" threshold */ + int flushed = 0; + for (;;) { + struct timespec a, b; + clock_gettime(CLOCK_MONOTONIC, &a); + HANDLE fslot = NULL; + ULONG fr = VHD_LockSlotHandle(stream, &fslot); + clock_gettime(CLOCK_MONOTONIC, &b); + if (fr != VHDERR_NOERROR) break; /* TIMEOUT/error => drained */ + long lock_ns = (b.tv_sec - a.tv_sec) * 1000000000L + (b.tv_nsec - a.tv_nsec); + VHD_UnlockSlotHandle(fslot); + if (lock_ns >= fast_ns) break; /* waited for a live slot => stop */ + if (++flushed > 8192) break; /* hard safety cap */ + } + if (flushed > 0) + fprintf(stderr, "[audio:%u] flushed %d stale slots on reader attach\n", + ps->port, flushed); + } + /* Reset wall-clock baseline after potentially blocking on open(). * Only used for the SILENCE fallback path (no hardware audio). */ struct timespec next;