### Initialize and Load Media with AetherEngine Source: https://github.com/superuser404notfound/aetherengine/blob/main/README.md Demonstrates basic initialization of AetherEngine and loading media from various sources, including options for HTTP headers and starting position. Use this for initial setup and playback initiation. ```swift import AetherEngine import SwiftUI let player = try AetherEngine() // SwiftUI: drop AetherPlayerSurface anywhere in the view tree var body: some View { AetherPlayerSurface(engine: player) } // UIKit / AppKit: bind an AetherPlayerView directly let surface = AetherPlayerView() player.bind(view: surface) try await player.load(url: videoURL) // or with a resume position try await player.load(url: videoURL, startPosition: 347.5) try await player.load(url: videoURL, options: .init( httpHeaders: headers, // attached to every demux + segment fetch matchContentEnabled: matchContent // tvOS Match Content master toggle )) try await player.reloadAtCurrentPosition() // background reopen, preserves options try await player.load(url: trackURL, options: .init(audioOnly: true)) // lean audio path ``` -------------------------------- ### Serve Media Stream Source: https://github.com/superuser404notfound/aetherengine/blob/main/docs/cli.md Starts the AetherEngine in serve mode, making the media stream available at a loopback URL. Other tools can then interact with this URL. ```bash curl -i http://127.0.0.1:/master.m3u8 curl -o /tmp/init.mp4 http://127.0.0.1:/init.mp4 mediastreamvalidator http://127.0.0.1:/master.m3u8 mp4dump --verbosity 1 /tmp/init.mp4 ffprobe -v debug /tmp/seg0.mp4 open 'http://127.0.0.1:/master.m3u8' # macOS QuickTime ``` -------------------------------- ### MinimalPlayer Source URL Configuration Source: https://github.com/superuser404notfound/aetherengine/blob/main/Examples/README.md Example of configuring the source URL for the MinimalPlayer SwiftUI app. ```swift @State private var sourceURL = URL(string: "https://example.com/your-video.mkv")! ``` -------------------------------- ### Create and Use FrameExtractor Source: https://github.com/superuser404notfound/aetherengine/blob/main/docs/formats.md Instantiate FrameExtractor either from the engine for loaded media or directly with a URL and headers. Prewarm is optional to hide cold starts. Use shutdown for explicit teardown. ```swift let frames = engine.makeFrameExtractor() // nil if nothing is loaded // or, for an arbitrary item (e.g. a Recents row): let frames = FrameExtractor(url: url, httpHeaders: headers) await frames.prewarm() // optional: hide cold-start at gesture begin let preview = await frames.thumbnail(at: 612.0) // CGImage?, nearest keyframe let still = await frames.snapshot(at: 612.0) // CGImage?, frame-accurate await frames.shutdown() // prompt teardown of the decode context ``` -------------------------------- ### Install AetherEngine via Swift Package Manager Source: https://github.com/superuser404notfound/aetherengine/blob/main/README.md Provides the Swift Package Manager dependency declaration for integrating AetherEngine into your project. Add this to your Package.swift file or Xcode project settings. ```swift .package(url: "https://github.com/superuser404notfound/AetherEngine", from: "3.12.0") ``` -------------------------------- ### Verify Developer ID Certificate Source: https://github.com/superuser404notfound/aetherengine/blob/main/Examples/DemoPlayerMac/README.md Before building the distribution, confirm that your Developer ID Application certificate is installed in your macOS keychain. This command lists all identities and filters for the required certificate. ```bash security find-identity -v -p codesigning | grep "Developer ID Application" ``` -------------------------------- ### Run AetherEngine Demo from Source Source: https://github.com/superuser404notfound/aetherengine/blob/main/Examples/DemoPlayerMac/README.md Execute this command in the Examples/DemoPlayerMac directory to build and run the demonstrator application locally. A window will open, allowing you to drag and drop video files for playback. ```bash swift run ``` -------------------------------- ### Enable Live and Timeshift Playback Source: https://github.com/superuser404notfound/aetherengine/blob/main/CHANGELOG.md Use `LoadOptions.isLive` to enable unbounded live mode. Pass `dvrWindowSeconds` to enable timeshift; omit it for live-only playback. ```swift let options = LoadOptions( isLive: true, dvrWindowSeconds: 1800 // Enable timeshift with a 30-minute window ) ``` ```swift let options = LoadOptions( isLive: true, dvrWindowSeconds: nil // Enable live-only playback ) ``` -------------------------------- ### AetherEngine Playback Transport Controls Source: https://github.com/superuser404notfound/aetherengine/blob/main/README.md Provides examples for controlling media playback, including play, pause, seeking, and rate adjustment. These methods are essential for user-interactive playback experiences. ```swift // Transport player.play() player.pause() player.togglePlayPause() player.setRate(1.5) // clamped to player.maxSupportedRate (2x video, 3x audio-only) await player.seek(to: 120) player.stop() ``` -------------------------------- ### Build Distribution DMG Source: https://github.com/superuser404notfound/aetherengine/blob/main/Examples/DemoPlayerMac/README.md This command initiates the build process for a notarized universal-binary .dmg file. It requires setting the DEVELOPER_ID and NOTARY_PROFILE environment variables. The script handles multiple phases including building, signing, notarizing, and packaging. ```bash DEVELOPER_ID="Developer ID Application: Your Name (TEAMID)" \ NOTARY_PROFILE="NOTARY_PROFILE" \ ./Scripts/build-dmg.sh ``` -------------------------------- ### Build and Test AetherEngine Source: https://github.com/superuser404notfound/aetherengine/blob/main/CONTRIBUTING.md Use these commands to build and test the AetherEngine Swift package from the command line. ```bash swift build swift test ``` -------------------------------- ### Run DemoPlayerMac from Command Line Source: https://github.com/superuser404notfound/aetherengine/blob/main/Examples/README.md Command to run the DemoPlayerMac SwiftPM application from the terminal. ```bash cd Examples/DemoPlayerMac swift run ``` -------------------------------- ### Open Live Custom Sources in Demuxer Source: https://github.com/superuser404notfound/aetherengine/blob/main/CHANGELOG.md Enable live custom sources to reach the native loopback by threading `isLive` into demuxer options via `Demuxer.open(reader:)`. This suppresses the duration-estimate SEEK_END that can stall forward-only readers. ```swift Demuxer.open(reader:) ``` -------------------------------- ### Connecting to SMB Share Source: https://github.com/superuser404notfound/aetherengine/blob/main/README.md Use AetherEngineSMB to connect to an SMB share and play media files. Ensure necessary network permissions and entitlements are configured. ```swift import AetherEngineSMB let smb = try await SMBConnection.connect( server: URL(string: "smb://nas.local")!, share: "media", path: "Movies/film.mkv", user: "alice", password: "s3cret" ) try await engine.load(source: .custom(SMBIOReader(source: smb), formatHint: "matroska")) ``` -------------------------------- ### Run Local HLS Live Fixture Server Source: https://github.com/superuser404notfound/aetherengine/blob/main/CHANGELOG.md Utilize `aetherctl hlsfixture` to run a local HLS live fixture server. This tool includes various fault knobs and a `--self-test` mode for end-to-end testing with `HLSLiveIngestReader`. ```bash aetherctl hlsfixture --self-test ``` -------------------------------- ### Live Playback with Software Path Source: https://github.com/superuser404notfound/aetherengine/blob/main/CHANGELOG.md Software-path live streaming uses a disk-spooled `PacketRingBuffer` for timeshift, retaining packets for the specified `dvrWindowSeconds`. ```swift // Software-path live (AV1-without-HW / VP9 / MPEG-2 / VC-1) // Unbounded live with no duration guard. Timeshift is backed by a disk-spooled, keyframe-indexed `PacketRingBuffer` that retains up to `dvrWindowSeconds` of packets; seek within the ring rewinds without a network round-trip. ``` -------------------------------- ### AetherEngine State and Clock Properties Source: https://github.com/superuser404notfound/aetherengine/blob/main/README.md Illustrates how to observe the playback state, duration, video format, and seeking status using Combine's @Published properties. Also shows how to access the precise playback clock for time-based operations. ```swift // State (Combine @Published) player.$state // .idle, .loading, .playing, .paused, .seeking, .error player.$duration player.$videoFormat // .sdr, .hdr10, .hdr10Plus, .dolbyVision, .hlg player.$isSeeking // true until a seek physically lands (programmatic + native scrubs) player.$seekTarget // in-flight seek destination (source-PTS), nil otherwise player.$currentAVPlayer // active AVPlayer, re-emitted on every reload (MPNowPlayingSession) // Time lives on player.clock, a SEPARATE ObservableObject, so the ~10 Hz ticks never fire objectWillChange on the engine (track lists / state views don't re-render per tick; native tvOS Menu dropdowns stay stable). player.clock.$currentTime // ~10 Hz playback clock (transport / scrub / resume) player.clock.$sourceTime // source PTS of the displayed frame (render subtitles against this) player.clock.$bufferedPosition // source-axis position buffered ahead; draw a buffer bar as bufferedPosition / duration ``` -------------------------------- ### Loading Live Streams Source: https://github.com/superuser404notfound/aetherengine/blob/main/README.md Load live streams with AetherEngine, optionally enabling DVR functionality. Live-only readers do not support seeking. ```swift // Live-only (seek() is a no-op), or live + timeshift: try await player.load(url: streamURL, options: LoadOptions(isLive: true)) try await player.load(url: streamURL, options: LoadOptions(isLive: true, dvrWindowSeconds: 1800)) ``` -------------------------------- ### Load Options for Preserving ASS Markup Source: https://github.com/superuser404notfound/aetherengine/blob/main/docs/formats.md Use LoadOptions with preserveASSMarkup set to true to opt out of ASS markup stripping. This allows hosts to render authored ASS styling themselves. ```swift LoadOptions(preserveASSMarkup: true) ``` -------------------------------- ### Store Notarization Credentials Source: https://github.com/superuser404notfound/aetherengine/blob/main/Examples/DemoPlayerMac/README.md Store your Apple notarization credentials in the keychain to avoid repeated prompts during the build process. Replace 'you@example.com' and 'YOURTEAM' with your actual Apple ID and Team ID, and 'xxxx-xxxx-xxxx-xxxx' with your generated app-specific password. ```bash xcrun notarytool store-credentials NOTARY_PROFILE \ --apple-id you@example.com \ --team-id YOURTEAM \ --password xxxx-xxxx-xxxx-xxxx ``` -------------------------------- ### Audio-Only Pipeline Logic Source: https://github.com/superuser404notfound/aetherengine/blob/main/docs/architecture.md Illustrates the conditional logic for audio-only playback based on codec whitelisting. This path bypasses video machinery for efficiency. ```text audioOnly == true ├─ whitelisted codec ──► AVPlayer (AudioAVPlayerHost) ──► AVR / speakers └─ otherwise ──► Demuxer ──► AudioDecoder ──► AVSampleBufferAudioRenderer ──► AVR / speakers ``` -------------------------------- ### Stable Live Target Duration Source: https://github.com/superuser404notfound/aetherengine/blob/main/CHANGELOG.md Live playlists now declare a generous, stable target duration from the first manifest, preventing startup failures for high-bitrate live sources. ```swift // Stable live `#EXT-X-TARGETDURATION`. // Live playlists declare a generous, stable target duration from the first manifest and hold the initial response until the first segment is ready, so high-bitrate live sources no longer fail at startup with `CoreMediaErrorDomain -12888`. ``` -------------------------------- ### Run SMB Throughput Test Source: https://github.com/superuser404notfound/aetherengine/blob/main/docs/cli.md Connects to an SMB2/3 share using SMBConnection and performs sequential throughput and random-seek consistency checks. This command is macOS-only and requires the AetherEngineSMB product. ```bash swift run aetherctl smbtest "smb://user:pass@host/share/path/to/file.mkv" --reads 128 ``` -------------------------------- ### aetherctl Built-in Fixture Subcommands Source: https://github.com/superuser404notfound/aetherengine/blob/main/docs/cli.md Commands that operate on built-in synthetic fixtures for live, DVR, and HLS testing. These do not require a media source URL. ```bash swift run aetherctl live # live MPEG-TS session against the built-in fixture ``` ```bash swift run aetherctl dvr # DVR rewind matrix across native + SW paths ``` ```bash swift run aetherctl hlsfixture # local HLS live fixture with fault knobs + ingest self-test ``` ```bash swift run aetherctl hlslive # SSAI live-direct-play repro against a synthetic ad-pod feed ``` -------------------------------- ### Live Playback with Native Path Source: https://github.com/superuser404notfound/aetherengine/blob/main/CHANGELOG.md A forward-only live producer cuts segments on the fly and serves a sliding HLS playlist to AVPlayer for native-path live streaming. ```swift // Native-path live (H.264 / HEVC / AV1-with-HW) // A forward-only live producer cuts segments on the fly and serves a sliding HLS playlist (advancing #EXT-X-MEDIA-SEQUENCE, no #EXT-X-ENDLIST, no #EXT-X-PLAYLIST-TYPE) to AVPlayer. ``` -------------------------------- ### aetherctl Core Subcommands Source: https://github.com/superuser404notfound/aetherengine/blob/main/docs/cli.md Commonly used subcommands for interacting with media source URLs. These commands perform actions like probing, serving, and validating streams. ```bash swift run aetherctl probe # dump container + streams + duration, exit ``` ```bash swift run aetherctl serve # park the engine's loopback HLS-fMP4 server ``` ```bash swift run aetherctl validate # serve + run mediastreamvalidator, exit ``` ```bash swift run aetherctl swdecode # open SoftwareVideoDecoder, decode N packets, report ``` ```bash swift run aetherctl dovitest # convert a DV Profile 7 stream to 8.1, dump for dovi_tool ``` ```bash swift run aetherctl extract # FrameExtractor still-image extraction + leak testing ``` ```bash swift run aetherctl audio [--seconds N] # audio-only pipeline smoke test (default 10 s) ``` ```bash swift run aetherctl customio # exercise the custom IOReader path end-to-end ``` ```bash swift run aetherctl seektest # rapid-seek burst repro + clock-bounce / isSeeking probe ``` ```bash swift run aetherctl # alias for serve (backwards compat) ``` -------------------------------- ### AetherEngine Track Management Source: https://github.com/superuser404notfound/aetherengine/blob/main/README.md Shows how to access and select audio and subtitle tracks, including handling sidecar subtitle files and clearing subtitles. Use this to provide users with track selection options. ```swift // Tracks player.audioTracks // [TrackInfo] player.selectAudioTrack(index: trackID) player.subtitleTracks // [TrackInfo], text + bitmap, one list player.selectSubtitleTrack(index: streamID) player.selectSidecarSubtitle(url: srtURL) // .srt / .ass / .vtt next to the media player.clearSubtitle() player.$subtitleCues // [SubtitleCue]: .text(String) or .image(SubtitleImage) ``` -------------------------------- ### aetherctl Network Share Subcommand Source: https://github.com/superuser404notfound/aetherengine/blob/main/docs/cli.md Command for playing files from an SMB2/3 share using the AetherEngineSMB reader. ```bash swift run aetherctl smbtest # play a file off an SMB2/3 share via the AetherEngineSMB reader ``` -------------------------------- ### AVIOReader Endless-Feed Mode Source: https://github.com/superuser404notfound/aetherengine/blob/main/CHANGELOG.md The demuxer AVIO no longer synthesizes EOF from a `Content-Length` header in live sessions, improving resilience to transient CDN drops. ```swift // `AVIOReader` endless-feed mode. The demuxer AVIO no longer synthesizes EOF from a `Content-Length` header in live sessions. Terminal error is reported only after reconnect retries are exhausted, so transient CDN drops don't terminate the session. ``` -------------------------------- ### Play Audio Through Audio-Only Pipeline Source: https://github.com/superuser404notfound/aetherengine/blob/main/docs/cli.md Plays a source through the audio-only pipeline, reporting the host used for playback. This exercises the same dispatch mechanism used by music hosts. ```bash swift run aetherctl audio ``` -------------------------------- ### Custom IOReader Implementation Source: https://github.com/superuser404notfound/aetherengine/blob/main/README.md Implement the IOReader protocol to provide custom data sources to AetherEngine. Seekable readers enable advanced features like track switching and background reloading. ```swift final class MyArchiveReader: IOReader { func read(_ buffer: UnsafeMutablePointer?, size: Int32) -> Int32 { /* ... */ } func seek(offset: Int64, whence: Int32) -> Int64 { /* ... */ } // AVSEEK_SIZE (65536) returns total size func close() { /* ... */ } // Optional (both have defaults). Override to unlock extra features: func cancel() { /* unblock a blocked read at teardown, do NOT invalidate the reader */ } func makeIndependentReader() -> IOReader? { /* a fresh cursor over the same source, or nil */ } } let probe = try await engine.load(source: .custom(MyArchiveReader(), formatHint: "mp4")) // load() returns the probe metadata it gathered (discardable). A one-shot // AetherEngine.probe(source:) without starting playback works too. ``` -------------------------------- ### AetherEngine Metadata and Now Playing Info Source: https://github.com/superuser404notfound/aetherengine/blob/main/README.md Demonstrates how to set external metadata for the Now Playing info on iOS and tvOS. This is useful for displaying track titles, artwork, and other relevant information to the user. ```swift // Info panel / Now Playing (iOS / tvOS) player.setExternalMetadata([ AVMetadataItem(/* title, artwork, etc. */) ]) ``` -------------------------------- ### Controlling Live Playback and Seeking Source: https://github.com/superuser404notfound/aetherengine/blob/main/README.md Control live playback by seeking to the live edge or a specific time. The player's clock provides information about the live range and position relative to the edge. ```swift // Drive a scrubber from the live-edge fields (they tick, so they live on player.clock): player.clock.$seekableLiveRange // ClosedRange?, session-relative; nil when DVR off player.clock.$behindLiveSeconds // seconds behind the edge; 0 at the edge player.clock.$liveEdgeTime await player.seekToLiveEdge() await player.seek(to: player.liveEdgeTime - 300) // 5 minutes back ```