fix: stop fudging playback rate; let video drive the timeline#595
Open
sshane wants to merge 1 commit into
Open
fix: stop fudging playback rate; let video drive the timeline#595sshane wants to merge 1 commit into
sshane wants to merge 1 commit into
Conversation
The video player was kept in sync with a virtual timeline clock by nudging videoElement.playbackRate by ±0.1 every 200-500ms whenever they drifted. Each playbackRate write hits the audio decoder, so on audio-sensitive paths (iOS Safari, CarPlay, AirPlay/Bluetooth, macOS audio routes) the audio crackled, stuttered, and dropped. Several layers of workarounds had grown around it: - iOS hid the playback speed UI entirely. - iOS skipped the rate-fudge step (so iOS audio was OK, but iOS video drifted from the timeline and `readyState` got pumped via a force-pause hack to "unstick" the buffer). - Firefox capped at 8x because it mutes audio above 8x. - HLS.js had a custom pause/play orchestration to work around the rate writes interfering with playback. This change inverts the model: the video plays at its declared rate and the timeline follows it, instead of the timeline driving the video. syncVideo now only acts on real divergence: - |diff| > 0.5s → push to video (user seek, loop wrap, initial sync). - |diff| > 0.05s while playing → pull the timeline to the video by dispatching a seek action (Redux only, no media-element touch). Buffering state switches to the browser's own waiting/playing events via ReactPlayer's onBuffer/onBufferEnd, replacing the readyState polling and the iOS-specific force-pause "fix". Drops the 16x cap and the Firefox 8x branch — playback rate is now whatever the user actually selected, not a moving target. Restores the speed UI on iOS, drops the now-unused isFirefox helper. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Welcome to connect! Make sure to:
deployed preview: https://595.connect-d5y.pages.dev |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
`syncVideo` was keeping the `
Layers of workarounds had grown around it:
This PR inverts the model. The video plays at its declared rate; the timeline follows it. `syncVideo` only acts on real divergence:
Buffering state moves to the browser's own `waiting`/`playing` events via ReactPlayer's `onBuffer`/`onBufferEnd`, replacing the `readyState` polling and the iOS-specific force-pause "fix". Drops the 16x cap and the Firefox 8x branch — playback rate is now whatever the user selected, not a moving target.
Restores the speed UI on iOS. Drops the now-unused `isFirefox` helper. `isIos` is kept for the legitimate platform difference in `onPlayerReady` (iOS Safari plays HLS natively, so audio-track detection has to read `videoElement.audioTracks` instead of hls.js's `hlsBufferCodecs` event).
Test plan
🤖 Generated with Claude Code