Repository navigation
feat(player): add AetherEngine as an opt-in fifth playback engine - #363
Merged
Merged
Conversation
AetherEngine (superuser404notfound/AetherEngine, exact 7.53.1) joins KSPlayer, VLCKit, AVPlayer and LumeEngine. It is declared last, so existing priority lists append it and KSPlayer stays the default. iOS, macOS and tvOS only; visionOS never links it. Lume reaches it only through the in-repo dynamic package LumeAetherBridge: importing it directly clashes with KSPlayer's FFmpegKit Libav* modules. Package traits stay off. Licences: LGPL-3 + App Store exception, FFmpegBuild LGPL 2.1 dynamic, libdovi MIT; notices in CreditsInfo. - Curated device-local options under player.aether.*, with iOS/macOS and tvOS settings screens, including Aether's own tvOS Match Content toggle - Full-screen playback, Multiview tiles and guide previews (embedded: muted, secondary output, no display criteria), full PiP, no timeshift - macOS gets com.apple.security.network.server for Aether's loopback HLS server - Shared player helpers replace per-engine copies: subtitle cue overlay, invisible button style, menu/play-pause presses, rate label, macOS hover reveal, Now Playing transport, engine failure policy, tile reconnects - 39 strings in all 10 languages; tests for options, load mapping, failure classification and engine priority Needs bilipp/LumeEngine#61 (CFFmpeg module map nested under Headers/CFFmpeg/), or LibDovi's module.modulemap collides with LumeEngine's.
Lume asked AetherEngine to hand every stream straight to AVPlayer (nativeRemoteHLS on), so Aether's own FFmpeg pipeline never ran: - Raw MPEG-TS live channels failed outright (AVPlayer: -12939, byte range and no content length) and fell back to the next engine. - Some live HLS channels played sound but never showed a frame. Native remote HLS now defaults to off, like the engine, and when turned on only applies to live sources whose URL is an HLS playlist. Live HLS goes through Aether's live-ingest reader instead, request headers included. Live loads also start reliably now: - The live join profile defaults to fast zap. Standard cuts 4 s segments and holds the first frame until ~18 s of a 1x origin has arrived, past the 15 s fallback watchdog. - A live load on the standard profile gets at least 35 s before the watchdog fires, above Aether's own 30 s first-serve deadline. - Probe size and analyze duration on Default cap live loads at 5 MiB / 5 s. The engine's 50 MiB / 60 s spent 16 s in find_stream_info on a channel carrying data-only streams. VOD keeps the engine default, and an explicit choice always wins.
…om:bilipp/Lume into feature/add-support-for-aetherengine-https
…iable An end-to-end run on an Apple TV 4K (tvOS 27.2) across live channels, VOD and every Aether setting turned up three Lume-side bugs. - Match Content off still switched the TV. The toggle fed the engine's matchContentEnabled, which only mirrors the system flag. It now picks who owns the display criteria (displayCriteriaOwner .engine / .host), so off leaves the TV in the format set in tvOS Settings. - Every zap stopped the session before loading the next channel. stop() resets the criteria to the menu's mode, so a UHD-to-UHD zap re-synced HDMI twice (~2.9 s each). A zap or reload now replaces the item in place (LumeAetherSession.prepareForReplacement(), then load). - A live source that goes quiet longer than the buffer (Sky Sport UHD on an Xtream panel: 13-25 s gaps) runs AVPlayer dry. AVPlayer pauses itself, the engine reports .paused, and Lume showed a frozen paused player with nothing to resume it. A live pause the viewer didn't ask for is now a stall: buffering UI, play re-asserted every 3 s, and a reconnect after 20 s. Recovered ~3 s after the source came back. The tvOS settings footer now says Native HLS only switches the frame rate for HDR video (the engine writes no criteria for SDR on that path), in all 10 languages. Also fixes the Arabic "%lld segments" entry, which failed ArabicLocalizationTests.
AetherEngine's live HLS ingest fetches four segments in parallel and hands the demuxer a segment only once it has arrived whole, so on a join the first segment shares the link with the next three. With an Xtream panel's 6-50 MB segments, that costs a second or more per zap. Live HLS loads now set maxConcurrentSourceRequests = 1. On an Apple TV 4K, 2 x 7 zaps: median open 1.65 -> 1.14 s, zap to playing 2.40 -> 1.94 s. The engine keeps the ceiling per origin for the rest of the process, so VOD from the same provider then also runs on one request. Measured on that provider (MKV, MP4, AVI), movie starts were no slower: 0.6-1.6 s capped vs 0.9-1.8 s uncapped. AGENTS.md no longer lists max concurrent requests among the options Lume never sets; it names this exception.
Bumps the exact pin in LumeAetherBridge and the credits tag URLs together. Transitive dependencies are unchanged. Measured on Apple TV 4K (tvOS 27.2) against LumeEngine: 7.54.0 now waits for the display's switch-end on rate-only mode changes (AE#950), which this TV never reports, so zaps that change frame rate hit the 2 s cap (median 3.34 s vs LumeEngine 1.14 s). DV profiles 20 and 4 still fail on the native path and fall back to LumeEngine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…subtitles, scrub log secrets - Live source reset: retry the engine in place (backoff 1/2/4 s, at most 3 within 60 s) before retuning, keeping the cache and the picture. Retune only when the engine declines, the budget is spent, or the playhead hasn't moved 2 s within 20 s; one 10 s extension while the engine is still rebuffering after it reconnected. - PGS, DVB and DVD subtitles reach SubtitleCueModel.bitmaps and are drawn on the video rect at their authored position. - A rejected TLS certificate maps to .unsupported so playback falls back instead of reconnecting to the same refusal. - Register the credentials only Lume can name with EngineLog per load (URL userinfo, short and long Xtream layouts, header values and their tokens) and release them at the next load or teardown.
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
Adds AetherEngine as a fifth playback engine alongside KSPlayer, VLCKit, AVPlayer and LumeEngine. It is opt-in and always last in the priority list, so nothing changes for existing users. Users who move it up get Aether's FFmpeg 8.1 + native-AVPlayer playback and a curated set of engine options.
Implementation
Importing AetherEngine directly into Lume fails: its
AetherLib*C modules redefine KSPlayer/FFmpegKit'sLibav*types. So Lume talks to it only through a new in-repo dynamic SPM package,LumeAetherBridge/. That package pins AetherEngine exactly at 7.53.1, uses library evolution andinternal import AetherEngine, and exposes a small API (LumeAetherSession,LumeAetherLoadRequest).nm -mshows each engine binding to its own FFmpeg. App-side wiring follows the LumeEngine template:AetherEngineCoordinator(+Failures/+Volume/+PictureInPicture)AetherEngineEngineViewandFullScreenPlayerView+AetherMultiViewAetherTileand thePreviewPlayerHandlecaseAetherEngineOptions(player.aether.*→AetherLoadPlan)AetherEngineSettingsViews(an iOS/macOS form and a tvOS detail)A simplify pass replaced per-engine copies with shared helpers used by all five hosts: subtitle cue overlay, invisible button style, menu/play-pause presses, rate label, macOS hover reveal, Now Playing transport,
EngineFailurePolicyand tile reconnect binding.Decisions
#if !os(visionOS),platformFilters,PlayerEngineKind.isAvailable).com.apple.security.network.serverfor Aether's loopback HLS server. iOS/tvOS reuse the existingNSLocalNetworkUsageDescription.MacPictureInPictureScaleron macOS.dvrWindowSecondsstays nil).UserDefaults, not synced. No SwiftData or CloudKit change.--enable-gpl/--enable-nonfree; libdovi MIT. Notices are inCreditsInfo. The existingfix-ksplayer-frameworks.shmin-OS rewrite also covers theAetherLib*frameworks (ITMS-90208). AetherEngine's privacy manifest bundle ships insideLume.app.Needs bilipp/LumeEngine#61. LibDovi's
Dovi.xcframeworkand LumeEngine'sFFmpeg.xcframeworkboth putmodule.modulemapat theHeaders/root, and the app build fails with "Multiple commands produce …/include/module.modulemap". #61 nests LumeEngine's module map. Until a LumeEngine release attaches the rebuiltFFmpeg.xcframework.zipand itsPackage.swiftURL/checksum move to it, CI and sideload builds of this branch will fail. Local builds work with a restructuredBinaryDependencies/.Testing
LumeTestssuite was not run.AetherEngineSettingsTests,AetherEngineFailureTests, plus priority/QoE/recording/preview casessessionwasn't@Published, which left the player view uninstalled..tsand HLS channels that failed or showed no picture now play on Aether.nativeRemoteHLSwas forced on. Fixed in b985032.Not yet verified:
AetherEngine's own logs include the redirected media URL (credentials redacted). That logging is inside the engine, not Lume.
Platforms
Related
Paired with bilipp/LumeEngine#61.