Skip to content

5.23.9 - AirPlay wireless hop

Choose a tag to compare

@superuser404notfound superuser404notfound released this 27 Jul 09:34

Patch release. Wireless AirPlay works again, and it now carries native subtitles as far as the receiver allows.

Fixed

The AirPlay hop rebuilt the session forever and never applied the LAN rewrite.

The reload that the external-playback observer starts tears down the very AVPlayer item that observer watches. AVPlayer therefore reported a transient "external playback ended" in the middle of it, which cleared the AirPlay flag before the load path read it. The rebuilt session served the loopback again, the receiver re-engaged external playback, and that edge started the next reload: one full session rebuild per turn, indefinitely, with 127.0.0.1 handed to a receiver that cannot reach it. An edge arriving during a session-preserving reload is now held and reconciled once the rebuilt item exists, against the live audio route rather than the player flag, because the route is what survives an item teardown.

5.23.8's subtitle fix was a no-op on DV-capable devices.

The rule that keeps a master for its subtitle renditions asked videoRange != .sdr || effectiveDvMode, and effectiveDvMode is a device capability, not a property of the content. On any DV-capable iPhone or iPad, SDR sources therefore took the HDR branch and lost their renditions anyway, on exactly the hardware the release was written for. The decision reads the real VIDEO-RANGE now.

Recovery paths pointed at the loopback.

The reactive master-rejection fallback reloaded 127.0.0.1/media.m3u8, as did the three reloads of the startup-readiness gate. All of them are rewritten onto the LAN address while AirPlaying, so a recovery actually reaches the receiver.

A receiver that refuses the playlist it was handed no longer parks the picture.

That refusal is silent: no -11868, no failed item, and the rate flickers to playing for a single tick so even hasEverPlayed latches, which is why the readiness gate could not see it. Progress is the only signal left, and the discriminator against a merely paused session comes from the loopback server's own account: a receiver that refuses fetches playlists and never a single segment. Five seconds of that now reloads the LAN media playlist, and the receiver is remembered by route UID for the rest of the process, so the cost is one delayed start rather than a stall on every title.

HDR and Dolby Vision over AirPlay

Whether an HDR master reaches the receiver is the receiver's decision, and it turns on its output mode. Measured on an Apple TV 4K with a DV Profile 8.1 4K source:

Receiver output format Master handed over Result
fixed 4K Dolby Vision 4K PQ + DV SUPPLEMENTAL-CODECS plays, subtitles travel
4K SDR, Match Dynamic Range on 4K PQ, every variation tried refused
4K SDR, Match Dynamic Range on SDR 1080p H.264 and 720p HEVC plays, subtitles travel

To get subtitles on HDR content over AirPlay, fix the receiver's video format to HDR or Dolby Vision. Offering the master a second time, to exploit the output switch the refused attempt triggers on a Match-Dynamic-Range receiver, was tried on device and only doubled the wait before the picture appeared.

Match Dynamic Range does not count as HDR readiness: it switches only when tvOS decides the content warrants it, which it never does for AirPlay content. This mirrors the rule the engine already applies locally, where an HDR source on a panel that is not in HDR mode is served the media playlist. Nothing in the manifest moves that decision, tested against a parked receiver: dropping the DV SUPPLEMENTAL-CODECS, clamping the declared BANDWIDTH, omitting RESOLUTION and declaring HDCP-LEVEL=TYPE-1 all left it refusing, and declaring the range as SDR over HDR content was disproven back in #98. The engine therefore offers the master, falls back when it is refused, and reports which playlist is in use through nativeSubtitleRenditionsServed.

Hosts

No public API change. Hosts that observe nativeSubtitleRenditionsServed get a value that describes the playlist actually served to the receiver rather than the one the local session resolved. Hosts that select a rendition on route changes can drop any re-assert loop: the AirPlay reload restores the selection by itself. Whichever surface renders the rendition, the host's own on-frame overlay should be hidden while it does, or the sending device draws the same lines a second time.

Verification

1108 tests, swift build -Xswiftc -strict-concurrency=complete clean, standalone iOS and tvOS builds without warnings. On device, iPhone 17 Pro to two Apple TV 4K receivers: SDR sources play with subtitles, a DV 4K source plays with subtitles on a receiver fixed to Dolby Vision, and a parked receiver recovers into playback in five seconds instead of showing AVKit's "not playable on this display" sign.

Acknowledgements

Reported by @thatcube, whose reading of the two code paths involved is what pinned the original issue to construction rather than to selection timing. The scope of the HDR limit comes from @DrHurt's caveat in #86, which turned out to be literal.