Skip to content

Emby: audio cuts out every few seconds on video-copy streams with converted DTS/TrueHD audio #420

Open

Description

@jlipworth

Summary

On Emby, playing a 4K HEVC HDR10 remux whose default audio track is DTS-HD MA 5.1 cuts the audio in and out about every 0.5–2 s, and A/V sync sometimes feels off. Emby copies the video and converts the audio to 5.1 AAC in fMP4 HLS (VideoCodec=copy, TranscodeReasons=ContainerNotSupported). Reproduced on macOS (Labstream 1.8.0, build 1567, and the current downloads/overhaul build) against Emby Server 4.10.1.0.

Root cause (server-side; Labstream works around it)

  1. Emby restarts the HLS transcode with -ss <segment × 6 s>:
    • by design on every seek or resume (segmentGap … max allowed gap is 4);
    • racily about 0.35 s into playback. AVPlayer asks for segment 1 while ffmpeg is still writing 1.m4s.tmp. Emby logs requestedIndex=1 and currentTranscodingIndex=2 and restarts instead of waiting about 70 ms. Its patched ffmpeg reports SegmentComplete … Index=1 for file _0, so this looks like an off-by-one; that part is inferred.
  2. The restarted transcode is misaligned. The copied video starts at the keyframe before the seek point; the converted audio starts exactly at it. On disk, ffmpeg's segments are aligned (within about 0.04 s). The segments Emby serves have each track rebased to zero separately, so audio leads video by about 0.75 s in every segment for the rest of the session.
  3. AVPlayer drops audio. CoreMedia logs Resyncing AQ timeline about every 4.6 s (2.05–2.56 s jumps) and discards audio buffers as sbufIsOld. Those are the audible gaps.

Evidence

Test Result
Labstream on the Emby stream (unified log) 48 AQ resyncs and 145 discarded audio buffers in 3 min
Bare AVPlayer test app on the same Emby URL (no Labstream code) Same pattern
Emby's exact served segment bytes, replayed from a local HTTP server Same pattern, so delivery is ruled out
Emby's logged ffmpeg command run directly, segments taken from disk Aligned; 0 resyncs
Uniform #EXTINF:6.0000 playlist over clean segments 0 resyncs, so the EXTINF mismatch is not the cause
DTS → AC3 conversion instead of AAC Still misaligned; resyncs
MPEG-TS segments Much worse (505 resyncs in 80 s)
Same-language AC3 5.1 track, audio copied Aligned; 0 resyncs, 0 discards

A side finding, not the cause: the converted audio's timestamps inherit millisecond rounding from the source track (frame steps of 984–1080 samples, not 1024). AVPlayer tolerated this in clean segments.

Fix (Labstream)

  • Copy-lane audio substitution (Emby only, a fallback). On the initial open, if PlaybackInfo says Emby will copy the video and convert the automatically selected audio, and the file has a same-language, same-role track the HLS profile copies (AAC/AC3; Emby converts E-AC-3 in this profile), re-negotiate PlaybackInfo with that track. A track the user picks manually in the player is honored as-is. Seeks and reopens keep the substituted track.
  • Playback details. The panel showed the source audio (e.g. DTS-HD MA) under "This device" because Emby reports only ContainerNotSupported. When the rendered audio codec family differs from the source, the lane now reads "Video is copied; audio is converted".

Remaining gates

  • Files whose only audio needs conversion (DTS/TrueHD-only) still hit the Emby bug. BreakOnNonKeyFrames=True has not been tested. This likely needs an upstream Emby report.
  • Cross-backend: Plex and Jellyfin take their own transcode paths and are not affected by this Emby-specific rebasing. Not re-verified as part of this fix.
  • Hardware/headset acceptance not run; verification was on the macOS host.

Activity

  1. added
    bugSomething isn't working
    playerIn-player UI / playback
    platform:macosNative macOS target or host tooling
    on Oct 26, 2026
  2. jlipworth commented on Oct 26, 2026

    @jlipworth
    OwnerAuthor

    Corrected root cause and the shipped fix (merged into downloads/overhaul as 81ece41)

    The original write-up blamed per-track timestamp rebasing after Emby's -ss restart, and proposed swapping to a copyable audio track. Further testing showed both were wrong.

    Actual cause: segment layout plus video back-pressure. Emby muxes each fMP4 HLS segment as one fragment, with every video sample ahead of the segment's audio. At the 6 s default, a 4K segment is about 30 MB. Labstream's HDR render path back-pressures the video, so AVPlayer only reaches a segment's audio about 2.5 s into that segment. CoreMedia discards it (sbufIsOld) and resyncs the audio queue (Resyncing AQ timeline, 2.05–2.56 s) about every 4.6 s.

    Configuration Audio-queue resyncs
    Labstream, 6 s segments, DTS→AAC 39–48 per ~3 min
    Labstream, 6 s segments, AC-3 copied 39 per ~5 min (so this is not codec-specific)
    Bare AVPlayer test app, same live Emby AC-3-copy stream, even with a 300 s forward buffer 0 (lighter render path)
    Labstream, 2 s segments, AC-3 copy 0, plus 1 on a single resume start
    Labstream, 2 s segments, DTS→AAC, including restarts at a resume and a deep seek 0 over 5 min
    Final build, DTS→AAC 0 over 3 min

    The ~0.75–0.85 s per-segment audio/video packing offset after a restart also appears with copied AC-3 that plays cleanly, so it is not the trigger by itself.

    Shipped:

    • The fMP4 video-copy lane requests SegmentLength=2 (EmbyVideoCopyPolicy). Emby honors it with -hls_time 2. The MPEG-TS static-recovery lane is unchanged.
    • Playback details: when the rendered audio codec family differs from the source, the lane reads "Video is copied; audio is converted" and the device card shows the delivered codec. The HLS probe now reads audio formats from the player item, because HLS assets expose no tracks.
    • The audio-track substitution was dropped. Conversion is fine once segments are short, so the user's selected track is never swapped.

    Verification: 1687 hermetic PMSKit tests pass; ci-hygiene passes; macOS host acceptance on this title for start, resume and deep seek. Every test session ended with DELETE /emby/Videos/ActiveEncodings and the transcode volume returned to empty.

    Still open:

    • Lip sync has not been checked by ear.
    • iOS/iPadOS/visionOS and physical hardware were not run.
    • One reopen failure was observed on the new build. It is tracked separately (see the linked follow-up issue).

    Follow-up for the reopen race: #421

  3. added 3 commits that reference this issue on Oct 26, 2026
    81ece41
    f440ab3
    cbaaf6a
  4. jlipworth commented on Oct 30, 2026

    @jlipworth
    OwnerAuthor

    Deep-seek follow-up (cbaaf6a5, see #421)

    The 2 s segment fix holds for steady playback, but a Mac soak showed audio-queue resyncs coming back on deep seeks. They track Emby encoder restart storms exactly: runs with 0–3 seek-gap restarts had no resyncs, and storm runs had about 10.

    The #421 fixes removed the client-caused storms. Across 20 deep-seek runs, audio-queue resyncs went from 61 to 23. Every remaining resync falls in runs with a server-side position reset, which is tracked in #421.

    Still open: lip sync has not been checked by ear; iOS/iPadOS/visionOS and hardware have not been run.

  5. jlipworth commented on Nov 5, 2026

    @jlipworth
    OwnerAuthor

    Landed on main in #425 (0b7f3fcb, tag v1.8.0). Any device or live acceptance gate already noted here still applies; the issue stays open until it's checked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingplatform:macosNative macOS target or host toolingplayerIn-player UI / playback

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions