Cloud welcome: stop the carousel pager reading AVPlayer time in the view body
Fixes #22708
Root cause
CloudWelcomeMediaCarousel draws its pager fill inside a TimelineView(.animation). On every frame the body called Playback.fraction, and that read AVPlayerItem.currentTime(). The call takes an AVFoundation lock (FigPlayerAsyncCopyBatchedNotificationSource). While the player is busy, for example when AVPlayerLooper swaps items or a decoder is being set up, the main thread blocked inside the view body. Sentry tracks this as CMUXTERM-MACOS-41S3: about 2.2k events from 293 devices on 0.65.x.
Fix
Playbacknow keeps a cachedPlayheadsample: seconds, duration, rate and when it was sampled. A periodic time observer on the main queue refreshes it every 0.25 s. AVFoundation also calls that observer on every jump, start and stop (seek, loop wrap, pause).fraction(at:)works out the current position from the cached sample and the frame's date. It clamps the result to 0...1, so theTimelineViewbody never calls into AVPlayer.- The observer token is removed when the movie detaches, when another movie attaches, or when the model is released.
- Before the first sample arrives (duration still NaN), or when there is no movie, the pager falls back to the wall clock as it did before.
Tests
CloudWelcomeTests.playbackFractionDoesNotQueryPlayer: about 2 s of frames (120 calls). It asserts zerocurrentItem/currentTime()reads on a countingAVPlayersubclass, and that progress rises steadily.CloudWelcomeTests.cachedPlayheadLifecycle: the fill holds while stopped, clamps at the end, ignores a NaN duration, and clears on detach.- Published head
d6d0b529ed0eed56901cfb59f6e0732a7a6166aa: CI compiled the macOS app/test products and executed all 28 Cloud welcome tests successfully. Local Swift syntax and test wiring passed.
Observed / Not run
The counting-player regression covers Playback.fraction(at:), not a rendered TimelineView. The native suite passed on the published head. A live AVFoundation mutex-hang reproduction and UI timing profile were not run.
Defaults chosen
- This reuses the commit first written for the hang-integration branch (https://github.com/manaflow-ai/cmux/pull/22901). That PR is stale and conflicting, so this ships the welcome carousel fix on its own against
main. - 0.25 s sample interval: wall-clock extrapolation between samples keeps the fill smooth at 60 fps.
- There is no separate red commit. The regression test uses the new cached-playhead API, so on the old code it fails to compile rather than failing on behavior.
Changelog
Fixed: Avoid blocking AVPlayer time reads while rendering Cloud welcome video progress.
🤖 Generated with Claude Code
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by CodeRabbit
- Improvements
- Movie progress in the welcome carousel now advances in line with playback speed and remains within the media’s duration.
- Progress is shown only when valid playback information is available, including after a player is attached or detached.