Fall back to wall clock after FFmpeg audio sink failure - #144
Blackspirits wants to merge 1 commit into
Conversation
Blackspirits
left a comment
There was a problem hiding this comment.
Final adversarial review on 2c444f33caeecc886804dabb6a25f60f7376c89d after CI SubtitleEdit#283: no blocker found. Rechecked write-rejection classification against concurrent seek/close, playing/paused clock rebasing, drain-only packet consumption after sink failure, and seek-driven recovery. The wall clock resumes from the same media position previously reported by the audio clock; stale/normal reset rejections do not trigger failover. Unknown-duration EOF remains explicitly outside this tranche. No merge/promotion performed.
Blackspirits
left a comment
There was a problem hiding this comment.
Final adversarial review on 2c444f33caeecc886804dabb6a25f60f7376c89d after CI SubtitleEdit#283: no blocker found. Sink rejection is classified as device failure only for the still-current/latest serial and outside close; failover preserves the media position already reported by the audio clock; paused state is preserved; drain-only audio prevents demux backpressure; seek/reset gets a deterministic recovery attempt. Unknown-duration EOF remains outside this PR. No merge/promotion performed.
Purpose
Dependent FFmpeg audio-runtime follow-up to #130 ("Fail closed when Core Audio queue cannot start").
#125/#128/#130 make sink writes/reset/start fail closed and make sink rejection observable to the audio decoder thread. This tranche handles the player-level consequence that remained: a real runtime sink failure could leave the player permanently anchored to an audio master clock that had stopped advancing.
This PR intentionally stays on #130's stack. It does not replace #116's unknown-duration EOF/drain work; it only changes runtime clock fallback and packet draining after an output failure.
Current upstream
SubtitleEdit/subtitleeditmain was rechecked at6c6b83dd043d8d38fb7a2b1800fdb9465526833b. The new upstream delta is Burn-in/encoder-settings work and does not touch the FFmpeg player or audio sinks. No competing upstream PR was found.Finding fixed
After an audio sink accepted at least one chunk, the player normally uses
audioAnchorPts + PlayedSeconds * audioSpeedas its master clock.For a real output failure on the still-current serial, no more PCM can be accepted while
PlayedSecondsstops advancing. Because_hasAudioremains true and the old anchor remains valid, the player could keep selecting a frozen audio master clock. Video presentation/end detection can then stall indefinitely.Simply terminating the audio worker is unsafe too: the audio packet queue can fill the shared demux budget and block video.
Fix
A rejected write is treated as a real device/output failure only when:
Seek/reset/close rejections remain normal interruptions.
For a real current-serial failure:
A later seek/reset clears the failed state and gives the sink one recovery attempt. If output still fails, the new serial deterministically falls back again.
Regression coverage
Pure tests pin:
Existing #125/#128/#130 serial/reset/start regressions remain unchanged.
Scope / branch state
8dab1f404370543ff639c23faa46f0f2c37e53de2c444f33caeecc886804dabb6a25f60f7376c89d6c6b83dd043d8d38fb7a2b1800fdb9465526833bScope note
Unknown-duration audio/video EOF and libswresample tail draining remain #116's responsibility. This tranche neither claims nor changes those semantics.
AI assistance: ChatGPT was used for adversarial sink-failure classification, master-clock failover modelling, packet-backpressure analysis, seek/close race review and focused regression design.
Final CI
Authoritative run: SubtitleEdit#283 on
2c444f33caeecc886804dabb6a25f60f7376c89dFinal adversarial review was performed on this exact HEAD after CI; no blocker found.