Skip to content

AetherEngine 5.18.4

Choose a tag to compare

@superuser404notfound superuser404notfound released this 22 Jul 04:30

Fixed

AetherPlayerSurface never rebinds on engine replacement, leaving fresh video black over audio (#188)

AetherPlayerSurface bound the engine to its platform view only in makeUIView/makeNSView; the update path was empty. When a host replaces its AetherEngine instance at the same structural position (a retry/reload flow that tears down and recreates the engine), SwiftUI reuses the platform view and calls only updateUIView:

new engine.boundView == nil          // bind(view:) never ran for the new engine
presentCurrentLayer() -> guard fails  // no-op, nothing attached
reused view still hosts old layer     // black video, audio plays
isReadyForDisplay == true throughout  // host layer reports ready, just not on-screen

Root cause. bind(view:) runs once, from makeUIView. On an engine swap SwiftUI does not remake the view (same structural identity), so the new engine is never handed the surface. Its boundView weak ref stays nil, the post-load presentCurrentLayer() bails on its guard let view = boundView, and the recycled view keeps showing the previous engine's now-detached layer.

Fix. updateUIView/updateNSView now call engine.bind(view:) on every update. bind is idempotent in steady state (existing === view skips the detach, presentCurrentLayer() re-attaches the same layer, and AetherPlayerView.attach short-circuits when the hosted layer is unchanged), so per-update passes are a cheap no-op swap. On an engine swap the new engine's bind points boundView at the reused view and re-attaches its layer, and any later post-load presentCurrentLayer() now has a bound view to attach to. Hosts that keyed the surface identity to the engine (.id(ObjectIdentifier(engine))) as a workaround no longer need to.

Covered by the new Issue188SurfaceRebindTests suite: a reused view bound to a second engine takes over its layer while the first engine's layer is dropped, and rebinding the same engine to the same view stays an idempotent no-op swap.

Acknowledgements

Root-caused and reported, with the suggested fix, by rrgomes (#188).

Full test suite: 942/942. macOS, iOS Simulator, and tvOS Simulator builds green.