AetherEngine 3.8.0
SMB2/3 playback (optional AetherEngineSMB product)
Play media off an SMB share through the normal decode path, with no server-side mount. SMB support ships as a separate, opt-in SwiftPM product so the SMB dependency never touches hosts that do not use it.
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)))How it works
SMBConnection(backed by AMSMB2 / libsmb2) is a read-onlyByteRangeSource.SMBIOReaderadapts it to the engine's existingIOReader, bridging each synchronous demux-thread read to AMSMB2's async API.- Seekable, so audio-track switching, background reload, embedded subtitles, and scrub previews all work (
makeIndependentReader()opens a second cursor on the same connection).
Licensing and isolation
AMSMB2 wraps libsmb2 (LGPL-2.1), the same license tier as the FFmpeg the engine already ships, so the LGPL profile is preserved. FFmpeg's GPL-only internal libsmbclient path is not used. The dependency is scoped to the AetherEngineSMB product, so the core engine and its tvOS hosts never link libsmb2.
Scope
Read-only, NTLMv2 / guest auth (no Kerberos). On tvOS the host declares the local-network entitlement to reach a LAN share. Not yet covered: directory browsing, reconnect/backoff, and SMB3 transit encryption. Validated off-device: builds for tvOS with no Kerberos/GSS symbols (CommonCrypto only), and aetherctl smbtest <smb-url> reads a file end to end with consistent random seeks.
Requested in #46 by @andrefmsilva.
Full changelog: CHANGELOG.md