Skip to content

6.15.0 - The route the session actually took

Choose a tag to compare

@superuser404notfound superuser404notfound released this 08 Aug 00:25
· 871 commits to main since this release

One addition: the engine now says which pipeline is actually serving the session. Drop-in from 6.14.0, no source change required on the consumer side.

The request was never the outcome

LoadOptions.nativeRemoteHLS records what the host asked for. The engine can change the route after that, on its own findings, and a host had no way to learn it had:

Move Trigger When
bypass -> ingest loopback #168 carriage watchdog: readyToPlay arrives, but AVFoundation builds no video track for a master that advertises one (HEVC in MPEG-TS) mid-session
bypass -> ingest loopback #199: that master's verdict is remembered, so the doomed mount is skipped at load
bypass -> ingest loopback AE#268: playlist plus the first segment's PMT identify a finite HEVC-in-MPEG-TS VOD at load
loopback -> bypass AE#154 / AE#246: an HLS playlist reached the loopback path, which cannot demux it at load

loadedOptions is internal, and playbackBackend reads .native for both native pipelines, so the split between them was invisible from outside. The mid-session reroute existed only as a log line.

videoRoute

player.$videoRoute   // .none / .remoteBypass / .loopback / .software / .audio
  • .remoteBypass is AVPlayer on the origin URL: no demuxer, no local server. AVFoundation owns media selection, buffering and subtitle drawing.
  • .loopback is the demuxer plus the local HLS-fMP4 server, the default video route. The engine owns the source connection and the subtitle pipeline.
  • .software, .audio and .none mirror the corresponding backends.

The value hosts most need it for is subtitle ownership: on the bypass AVPlayer draws the origin's own legible renditions, on the loopback and the software path the host's renderer does. A host that guesses wrong draws nothing, or draws every cue twice.

It is derived, not a second copy of the session state: a pure fold over playbackBackend and the session's effective options, recomputed from each one's didSet and assigned only on a real change. That is the arrangement playbackPhase uses, and it is what keeps a reroute added later from being able to forget the route, since every reroute already writes one of those two properties.

Two properties of the value worth knowing before you write against it:

  • A declared bypass is not a route. Until a backend exists the value stays .none, so a load that reroutes before it ever mounts natively never publishes a bypass it did not take.
  • Teardown drops it back to .none, like every other per-session published value.

playbackBackend stays what it was, a diagnostic. Branch on videoRoute.

Verification

1606 tests in 238 suites, -strict-concurrency=complete clean, tvOS and iOS Simulator builds green. On real media: a local MP4 settles on route=loopback, and Apple's bipbop_adv_example_hevc master takes the AE#154 reroute and publishes remoteBypass at the moment of the reroute, with no .loopback emission in front of it.

aetherctl play now prints route= next to backend=, so the value is capturable from the harness without a device.