Skip to content

6.5.0 - Engine errors render what they already compute

Choose a tag to compare

@superuser404notfound superuser404notfound released this 02 Aug 10:19

A load that failed reported "The operation couldn't be completed. (HLSIngestError error 0.)" while the engine already knew, and had already formatted, the HTTP status behind it.

Fixed

  • A terminal error now says what went wrong. Terminal states are published as state = .error("Failed to load: \(error.localizedDescription)"), and the engine's error enums were only CustomStringConvertible. localizedDescription does not reach description, so Foundation's generic bridge answered The operation couldn't be completed. (HLSIngestError error 0.). The status HLSLiveIngestReader resolved was raised correctly and rendered correctly, then dropped at the boundary between them, which left an origin refusing a transcode with 500 indistinguishable from a corrupt file.

    Fixed as a class rather than at the call sites. Every error type the engine can throw now conforms to LocalizedError with errorDescription returning the description it already computes, so the same change covers the boundaries the report did not name: AetherEngine+Loading publishes "Reload failed: ..." and "Audio track switch failed: ...", and SoftwarePlaybackHost / AudioPlaybackHost route "Playback error: ..." through onError.

    Keeping localizedDescription at those call sites is deliberate. URLError and other NSErrors reach the same catch blocks, and there it is the better rendering while "\(error)" would be a domain dump. Conforming the enums makes both sides right at once.

  • DemuxerError renders its AVERROR code. It is the most common failure at the load boundary and carried no description at all, so the code, which is the whole diagnosis, was lost twice over. It now reads through av_strerror:

    Demuxer: open failed (Invalid data found when processing input (-1094995529))
    

    Also given descriptions: DiscError, SubtitleDecoderError, FrameDecodeError, AudioDecoderError, both audio-tap error types and the two AetherEngineSMB error structs. Already-described types gained the conformance alone: AVIOReaderError, HLSLocalServerError, ProducerError, MuxerError, AudioBridgeError, and both diagnostics probes.

Reported by @edde746, traced from the raise site to the render site (#283).

Added

  • LocalizedError conformance on the public error types. HLSIngestError, PacketTimingProbe.ProbeError, AudioTapProbe.ProbeError, SMBURL.ParseError and SMBConnection.SMBError gain public conformance and an errorDescription. That is added public API, which is why this is a minor rather than a patch.

Compatibility

No removals or renames. One behaviour change worth knowing about: a host that renders a caught engine error with localizedDescription, or that surfaces PlayerState.error, sees different text on this version. The new text is the description those types already published, so anything logging "\(error)" is unchanged, and anything matching on typed cases is unaffected. Text matching against the old Foundation bridge string is the one pattern that breaks, and it could not have carried information anyway.

Not addressed, and not the same defect: a mid-session failure on the nativeRemoteHLS bypass arrives as AVPlayerItem.error, an NSError from AVFoundation whose localizedDescription is already correct.

Upgrading

.package(url: "https://github.com/superuser404notfound/AetherEngine", from: "6.5.0")