Summary
Resuming a Dolby-Vision MKV through the Plozzigen/AetherEngine hybrid engine intermittently freezes for ~28s (black screen, audio silent, last subtitle stuck on screen) before recovering. Root-caused with on-device instrumentation: AVPlayer wedges — after the async DV HDMI mode-switch resets AVPlayer's loopback HLS connection mid-fetch on the first resume segment (while its buffer is still empty), AVPlayer enters AVPlayerWaitingToMinimizeStallsReason and never re-requests the segment, so playback deadlocks until the app-level watchdog fires at ~30s. This is an AetherEngine-level issue (DV display switch × loopback HLS × AVPlayer), not SMB- or transport-specific — it will affect any DV source that routes through the hybrid engine.
Steps to reproduce
- Resume (not start-from-0) a 4K Dolby Vision (Profile 8.1,
DOVIWithHDR10) MKV that routes to Plozzigen.
- Watch the first frame appear, then freeze.
- Intermittent — it's a timing race, but resuming the same file at the same position reproduces it often.
Expected behavior
Playback continues within a second or two of the first frame, every time.
Actual behavior
~28s freeze (black, no audio, stale subtitle), then the app watchdog tears down and recovers (or cross-source fails over to another server's copy).
Affected backend(s)
SMB share
Plozz version & build
Dev branch thatcube-assess-emby-support, AetherEngine diagnostic pin f1a3c56 (= d97fad24 + [LagDiag]-to-journal instrumentation).
tvOS version
tvOS (Apple TV 4K, current dev toolchain)
Apple TV model
Apple TV 4K
Logs / screenshots
Definitive proof (on-device [LagDiag] journal, 1 Hz, during the freeze):
GET /seg539.mp4 ← first resume-segment fetch (buffer empty)
[DisplayCriteria] WARN switch ended (~1550ms) but EDR headroom still 1.0 (panel stayed SDR despite HDR criteria)
first-frame
[LagDiag] clk=2696.96 tcs=waiting wait=AVPlayerWaitingWhileEvaluatingBufferingRateReason req=4 dreq=0 empty=n
send failed for /seg539.mp4: errno=54 ← AVPlayer resets its own loopback connection (ECONNRESET) during the DV flip
[LagDiag] clk=2696.96 dclk=0.00 tcs=waiting wait=AVPlayerWaitingToMinimizeStallsReason req=4 dreq=0 empty=y
[LagDiag] ... req=4 dreq=0 empty=y ... ← repeats UNCHANGED for 27 ticks (~28s)
engine RETRY_FRESH (app watchdog @ ~30s)
Key signals:
req=4 dreq=0 frozen for the entire freeze — AVPlayer stops issuing GETs entirely; it never re-requests the reset segment. Proves an AVPlayer-side wedge, not a server/producer/SMB fault (during the freeze the SMB producer keeps reading fine).
wait=AVPlayerWaitingToMinimizeStallsReason + empty=y — AVPlayer waits to minimize stalls with an empty buffer while fetching nothing to fill it.
errno=54 (ECONNRESET) lands ~200ms after the DV switch "ends" — the flip disrupts AVPlayer's in-flight fetch.
Differentiator (why it's sometimes instant): the same session captured a recovering case — when the reset landed with data already buffered (fwd=4.0), AVPlayer re-requested (req 5→9) and moved to the next segment. So: reset on the first segment with an empty buffer → wedge; reset with a non-empty buffer → survives. It's a race between the async, app-invisible DV HDMI flip and AVPlayer's first fetch.
Constraint on any fix: DV Profile 8.1 decode requires the display criteria set before decode starts (the load-bearing pre-play settle), and the flip is async + unobservable (currentEDRHeadroom stays 1.0), so the flip inherently lands after playback begins. The existing "settle DV on notifications" fix (8c1f979, already in d97fad24) only reduced first-frame latency; it does not prevent this wedge.
Fix direction (to design/upstream in AetherEngine, later): make the first post-seek fetch survive the flip — e.g. a tiny/pre-warmed first segment at seek so it's fully buffered before the flip can reset it (turning every case into the "recovering" path), or an engine-side detect-and-nudge (playImmediately/micro-seek) when tcs=waiting + empty=y + req frozen shortly after first-frame. Deprioritized for now; filing with proof so it isn't lost.
Summary
Resuming a Dolby-Vision MKV through the Plozzigen/AetherEngine hybrid engine intermittently freezes for ~28s (black screen, audio silent, last subtitle stuck on screen) before recovering. Root-caused with on-device instrumentation: AVPlayer wedges — after the async DV HDMI mode-switch resets AVPlayer's loopback HLS connection mid-fetch on the first resume segment (while its buffer is still empty), AVPlayer enters
AVPlayerWaitingToMinimizeStallsReasonand never re-requests the segment, so playback deadlocks until the app-level watchdog fires at ~30s. This is an AetherEngine-level issue (DV display switch × loopback HLS × AVPlayer), not SMB- or transport-specific — it will affect any DV source that routes through the hybrid engine.Steps to reproduce
DOVIWithHDR10) MKV that routes to Plozzigen.Expected behavior
Playback continues within a second or two of the first frame, every time.
Actual behavior
~28s freeze (black, no audio, stale subtitle), then the app watchdog tears down and recovers (or cross-source fails over to another server's copy).
Affected backend(s)
SMB share
Plozz version & build
Dev branch
thatcube-assess-emby-support, AetherEngine diagnostic pinf1a3c56(=d97fad24+[LagDiag]-to-journal instrumentation).tvOS version
tvOS (Apple TV 4K, current dev toolchain)
Apple TV model
Apple TV 4K
Logs / screenshots
Definitive proof (on-device
[LagDiag]journal, 1 Hz, during the freeze):Key signals:
req=4 dreq=0frozen for the entire freeze — AVPlayer stops issuing GETs entirely; it never re-requests the reset segment. Proves an AVPlayer-side wedge, not a server/producer/SMB fault (during the freeze the SMB producer keeps reading fine).wait=AVPlayerWaitingToMinimizeStallsReason+empty=y— AVPlayer waits to minimize stalls with an empty buffer while fetching nothing to fill it.errno=54(ECONNRESET) lands ~200ms after the DV switch "ends" — the flip disrupts AVPlayer's in-flight fetch.Differentiator (why it's sometimes instant): the same session captured a recovering case — when the reset landed with data already buffered (
fwd=4.0), AVPlayer re-requested (req 5→9) and moved to the next segment. So: reset on the first segment with an empty buffer → wedge; reset with a non-empty buffer → survives. It's a race between the async, app-invisible DV HDMI flip and AVPlayer's first fetch.Constraint on any fix: DV Profile 8.1 decode requires the display criteria set before decode starts (the load-bearing pre-play settle), and the flip is async + unobservable (
currentEDRHeadroomstays 1.0), so the flip inherently lands after playback begins. The existing "settle DV on notifications" fix (8c1f979, already ind97fad24) only reduced first-frame latency; it does not prevent this wedge.Fix direction (to design/upstream in AetherEngine, later): make the first post-seek fetch survive the flip — e.g. a tiny/pre-warmed first segment at seek so it's fully buffered before the flip can reset it (turning every case into the "recovering" path), or an engine-side detect-and-nudge (
playImmediately/micro-seek) whentcs=waiting+empty=y+reqfrozen shortly after first-frame. Deprioritized for now; filing with proof so it isn't lost.