fix(native): the media fallback returns to the recovery position and keeps a pause - #11
Conversation
… placed (superuser404notfound#98) The superuser404notfound#98 media fallback replayed the start position of the session's first mount. The superuser404notfound#93/superuser404notfound#65 stage-2 recovery swaps a fresh item in at the position playback held, so when that recovery item was refused at startup, the fallback rewound the session to wherever it had first been loaded. Field log, Apple TV 4K 3rd gen, tvOS 27.0, HDR10+ HEVC Matroska opened with a resume at 1844 s: paused at 2099.69 s, the item died behind the screensaver, the recovery item was refused with -11868, and playback resumed at 1834.79 s. A title started from its beginning resumes at its first frame. NativeAVPlayerHost now records where each mount places its item, in-place swaps included, and the fallback reads that instead of the engine's first-mount copy. The first mount records the same value as before, so a fallback of a first mount is unchanged. (cherry picked from commit f36fe40)
…ng (superuser404notfound#98) When a dead item's recovery reload was refused (-11868), fallBackToMediaPlaylist swapped in the media playlist and called play() unconditionally, so a title paused behind the tvOS screensaver started itself. The item-death reload now keeps the viewer's pause (clearing the host's play intent), and the fallback reads that same intent before it plays. Ports the fallback half of upstream superuser404notfound#623; the reload half is covered by this fork's own item-death change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Providing Context (Files & MCPs)Add these hints in your PR description (or a comment) to unlock deeper checks:
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (6)
💤 Files with no reviewable changes (1)
Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughVOD media fallback now resumes at the rejected item’s mounted position and calls ChangesMaster fallback recovery
Priority: ➖ Normal Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to The fallback is ready for normal merge checks; device behavior has not been verified. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The change is confined to playback recovery. It does not appear to add an externally callable control or expand access to data or privileges. Device behavior and some surrounding code were not fully verified. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 3 files. (2 skipped: 2 unsupported.)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5e7cec9c1a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…to resume The fallback read only the host's play intent, which a Play from AVKit, Control Center or PiP never sets. A viewer who started an autoplay=false mount from the transport bar, or pressed Play from AVKit after a paused item-death reload, got a paused fallback. The host now decides at the refusal: the item plays on unless the viewer paused it before the refusal (the item-death one-second margin), and only if the engine's intent or AVPlayer's rate says it was told to play. When it stays paused the fallback calls pause() so a latched intent cannot restart the fresh item on readyToPlay. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Providing Context (Files & MCPs)Add these hints in your PR description (or a comment) to unlock deeper checks:
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0c4dff5109
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…at the refusal Three races in the previous verdict, raised in review: - An engine pause less than a second before the refusal falls inside the failure margin, and the per-load roll flag still said the item had played, so the fallback resumed a paused title. - The fallback runs a task hop after the refusal; a Play or Pause pressed in between was overwritten by the verdict taken earlier. - The verdict was taken in the status KVO hop, which can run before the rate KVO hop that records a Play from AVKit. The host now records when the master was refused and any engine command since, and the engine asks for the verdict inside fallBackToMediaPlaylist, before the swap. A roll counts only if AVPlayer reported it after the engine's last stop, so an engine pause clears it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Providing Context (Files & MCPs)Add these hints in your PR description (or a comment) to unlock deeper checks:
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: adff22aaa9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…item dies (#551) Moves the AetherEngine pin to b1e4879e, which includes Silo-Server/AetherEngine#10 (the item-death reload keeps a viewer's pause) and Silo-Server/AetherEngine#11 (the media fallback returns to the recovery position and plays only for a viewer who was playing). Refs #549 Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Summary
After #10, a paused title whose player item dies still restarts from where the session was first opened, and still starts playing, when AVPlayer refuses the recovery item's master. Both problems are in
fallBackToMediaPlaylist: it reloads at the first mount's start position and callsplay()unconditionally. This PR ports the two upstream fixes for that path.Part of Silo-Server/silo-apple#549 (the "from the start" half).
What changed
The media fallback reloads where the refused item was placed.
NativeAVPlayerHostrecords the start position of every mount, in-place swaps included, and the fallback reads that in place oflastNativeVideoStartPosition, which only the first mount wrote. Cherry-picked from upstream fix(native): the media fallback comes back where the refused item was placed (#98) superuser404notfound/AetherEngine#621.The media fallback plays only when the refused item was playing, or was told to play, and the viewer had not paused it.
fallBackToMediaPlaylistaskshost.mediaFallbackResumesPlaying()when it runs, before the swap:When the fallback stays paused it calls
host.pause(), which clears a latched intent. This covers what fix(native): a recovery reload leaves a paused viewer paused (#93) superuser404notfound/AetherEngine#623 does for the fallback, but reads the rate as well as the intent.CHANGELOG.mdentries for both changes.Test plan
swift build,swift test). Not run on an Apple TV. There is no hook to force a display rejection, so the fallback call site is covered by the same source-reading test upstream uses.a02975e:swift testpasses locally: 3,395 Swift Testing tests, 636 XCTest tests (1 skipped), and the 43 authorization tests run separately, as in CI, onadff22aa. New tests: the placement tests from fix(native): the media fallback comes back where the refused item was placed (#98) superuser404notfound/AetherEngine#621 (a recovery swap moves the recorded placement, a mount with no start position is placed at the head, a live rejoin records none), pure-decision tests for the fallback's resume rule (engine Play, AVKit Play, a pause before the refusal, an engine pause inside the margin, a command after the refusal), a host test that engine Play and Pause drive the verdict, and a call-site check that the verdict is read before the swap.Known gap: a pause from AVKit, Control Center or PiP less than a second before the refusal cannot be told apart from the refused item's own stop, so that fallback plays. #10 has the same margin. A pause through the engine is handled.
Not addressed: the refusal still sets
panelRefusedHDRMasterfor the process (superuser404notfound#588), so HDR titles after it play media-direct until the app returns from the background.Checklist
CHANGELOG.mdupdatedfeat(...),fix(...),chore(...))AI disclosure
claude-opus-5-5🤖 Generated with Claude Code