HLS Audio and Video Drift After an Ad Break or Encoder Restart

Trace HLS lip-sync drift across ad insertion and encoder restarts by comparing timestamps, discontinuity sequences, renditions, and browser playback evidence.

When speech no longer matches a speaker's mouth after an ad break, channel change, or encoder restart, the visible symptom does not identify the fault. A playlist boundary may be wrong, audio and video timestamps may diverge, one rendition may be misaligned, or the player may be rendering a different track than the one being inspected.

The reliable approach is to compare the same timeline checkpoints across the video and audio media playlists, then correlate those checkpoints with parsed timestamps and playback events. Test only streams you own or are authorized to inspect. Remove signed URLs, keys, cookies, tokens, viewer IDs, and private hostnames from logs.

Verification method — September 26, 2026: We ran a deterministic Node.js 24.12.0 fixture using synthetic video/audio presentation timestamps and discontinuity sequence numbers. It confirmed a stable 40–60 ms offset across a splice, detected a synthetic audio-only 500 ms offset increase, and distinguished that case from a shared timestamp reset. This verifies only fixture arithmetic and checkpoint matching. It does not parse transport streams or fMP4, run an encoder, play an ad, test a browser/player/device, or establish a universal acceptable lip-sync threshold. The fixture is scripts/test-hls-av-sync-fixture.cjs.

First decide what “drift” means

Capture whether the error is constant, cumulative, or introduced at one boundary. Note which audio rendition is selected and whether the video quality changed at the same time.

SymptomFirst hypothesis to testEvidence to compare
Same offset before and after a spliceA pre-existing encode or output-path offsetPaired audio/video timestamps well before the boundary
Sudden offset change at an ad or restartBad splice timestamp mapping or an unmarked timeline resetLast content segment and first inserted/restarted segments
Offset grows throughout a long programClock-rate or timestamp progression mismatchSeveral checkpoints over time, not only segment starts
Only one quality level driftsRendition-specific timing or mux issueMatching content time across every video playlist
Only one language track driftsAlternate-audio packaging or timestamp alignmentSelected audio playlist against the same video rendition
Offset changes when the browser seeks or switches tracksPlayer buffering/switch path may be involvedParsed media timestamps plus player events and current track IDs

Do not adjust audio delay until you know which pattern you have. A constant correction can hide a splice defect and make other segments wrong.

Compare matching checkpoints, not segment numbers

Media sequence numbers identify playlist positions; they do not guarantee that audio and video segments with the same number cover the same instant. Align observations by program date-time when present and unambiguous, content/ad boundary, segment presentation interval, and discontinuity sequence. Record the playlist snapshot and fetch time because live playlists move.

For each checkpoint, note:

  • Video rendition and audio rendition/group selected.
  • Segment URI identity in a sanitized form, media sequence, discontinuity sequence, duration, and program date-time if available.
  • First and last presentation timestamps from an authorized media analyzer.
  • Whether the playlist contains EXT-X-DISCONTINUITY at that boundary.
  • The first content segment after the ad and the first segment after an encoder restart.
  • Any timestamp wrap, reset, gap, overlap, or track change reported by the demuxer.

Keep raw media local and access-controlled. A diagnostic report usually needs timestamp values and segment labels, not the media or a reusable URL.

Audit discontinuities across every rendition

RFC 8216 defines EXT-X-DISCONTINUITY-SEQUENCE so clients can synchronize renditions whose playlists contain discontinuities. Apple’s authoring guidance says encoding-continuity breaks need a discontinuity tag and that variants and renditions must mark discontinuities at the same points in time. A tag in only one playlist can leave switching ambiguous even when each individual playlist appears plausible.

At each splice or restart, compare the relevant video playlists and each selectable audio playlist. Verify the discontinuity count and boundary refer to the same program instant; do not merely compare line numbers. If a sliding live playlist has removed earlier discontinuities, confirm its sequence base advances consistently. Where EXT-X-PROGRAM-DATE-TIME is used, verify that the mapping is not ambiguous across the boundary.

Also inspect the media timeline itself. A playlist tag communicates a boundary; it does not repair an audio timestamp that jumps by half a second or a video track that continues on a different clock. For fMP4, inspect decode-time continuity as well as presentation timestamps. For MPEG-TS, inspect timestamp progression and continuity around the splice.

Trace the first bad boundary through the player

For an MSE-based hls.js path, capture the library version, level and audio-track changes, fragment loading/parsing events, errors, and LEVEL_PTS_UPDATED data where exposed by the installed version. Correlate those events with video.currentTime, video.audioTracks where supported, and the rendered symptom. Native HLS implementations may not expose the same internals; use their available diagnostics and label the missing evidence.

Do not infer demuxed PTS directly from wall-clock time. Keep monotonic event timing separate from media timestamps. A page can also resume after background throttling with stale buffers or an expired live window; if the issue only occurs after a lock or tab switch, compare against the background recovery guide. For playback stalls during the same investigation, see HLS buffering diagnosis.

Use a controlled reproduction matrix

On a stream and insertion workflow you are authorized to test, replay the same segment set and change one factor at a time:

CaseWhat it isolates
No ad, continuous encoderBaseline timestamp relationship
Ad inserted with the same encoder clockSplice mapping without a clock reset
Encoder restart without an adRestart/discontinuity handling
Ad plus encoder restartInteraction between splice and timestamp reset
Each video rendition with default audioVariant alignment
Each alternate audio track with one fixed video renditionAudio rendition alignment
Seek across the boundary and switch tracks on both sidesPlayer transition behavior

Save playlist snapshots and approved analyzer output at each transition. Compare the last clean pre-boundary interval, the first interval after it, and several intervals farther ahead. If the offset jumps once and then stays constant, investigate the splice mapping. If it keeps growing, investigate clock progression. If only one rendition differs, fix packaging for that rendition rather than applying a global player delay.

Choose the fix at the layer that owns the mismatch

  • Boundary absent or inconsistent: correct playlist generation and discontinuity sequence across all affected variants and renditions.
  • Timestamps jump only in inserted media: correct the packager or ad-stitcher timestamp mapping; validate both sides of the splice.
  • One track drifts progressively: inspect its encoder clock, sample timing, and mux; do not compensate every rendition.
  • Only a player switch reproduces it: reduce the case to a minimal authorized fixture, capture exact library/browser versions and events, then investigate buffering/remux behavior.
  • Only a live resume reproduces it: refresh the playlist and establish the current seekable window before restoring position; do not reuse a stale absolute currentTime blindly.

Retest the entire window before and after the change, all supported renditions, track switches, and seek paths. Keep any intentional offset documented at the correct output stage, not hidden in a viewer-side permanent delay.

Report evidence without overclaiming

A useful report states the selected tracks, boundary type, playlist sequence values, timestamp offset before and after, whether the offset then grows, the player path and versions, and the exact reproduction case. Distinguish a synthetic fixture, a static playlist review, an analyzer measurement, and physical playback. They answer different questions.

Primary references

Start at the first boundary where paired audio/video timing changes. Matching playlist discontinuities, rendition-wide timing, parsed timestamps, and player events together will show whether the owner is the packager, ad stitcher, encoder, player transition, or live-resume path.