PrismCore / API reference / Engine and session

Enumeration

PrismCoreError

enum PrismCoreError

Declared in Sources/PrismCore/PrismCoreError.swift · PrismCore 3.5.4

Why a session failed, in terms a host can branch on.

Before this existed a host got SessionError.startupTimedOut(underlying:) wrapping an FFmpegError whose only distinguishing feature was an English string from libavformat — so "your token expired", "the server is throttling us", "this file has no video" and "the disk is full" were all one failure with four different remedies. Every case here is something the engine observed; when it did not observe enough to tell two situations apart they share one case rather than getting a guess each, because a host that re-authenticates against a rate limit is worse off than one that saw .unknown and retried.

Nothing throws this type in place of an existing error: start() still throws PrismCoreSession.SessionError, the probe still throws SourceProbe.Failure. classify(_:) turns any of them — including the AVPlayerItem.error the host reads back out of AVFoundation — into this.

Cases

case originRefused(status: Int?, url: URL?)

The origin answered, and the answer was "not for you": 401, 403, 407. An expired Plex token, a share whose link was revoked, a proxy wanting credentials. status is nil when the refusal arrived as a URLError rather than as a response we could read a code off.

case originRateLimited(status: Int, retryAfter: TimeInterval?, url: URL?)

The origin answered, and the answer was "not now": 429, 503, 509. retryAfter is the origin's own Retry-After, in seconds, already resolved from either form (delta or HTTP date); nil means it did not say and the caller's own backoff applies.

case originUnreachable(status: Int?, url: URL?, underlying: (any Error)?)

The origin did not serve the bytes, and did not refuse us either: a dropped connection, a host that stopped resolving, a 404, a 5xx.

This is also what "the origin vanished mid-session" looks like — and deliberately so, because at the failure site the two are the same observation. A connection reset on the first read and one on the thousandth carry identical evidence. The host already knows which it is, from whether start() had returned: a throw out of start() is an origin that was never usable, a remuxFailure appearing afterwards is one that went away. Claiming that distinction here would mean inferring it from state the error does not carry.

case noVideoStream

The container opened and was described, and it carries no video stream. An audio-only .mka, a cover-art-only container.

Not "the probe failed" — that is .unknown or an origin case. This is only thrown after avformat_find_stream_info returned success and the stream list was walked, so it is a fact about the source rather than a fact about how far we got.

case videoCodecNotRemuxable(codecName: String, streamIndex: Int)

The container is readable and the video codec is known, but it cannot be stream-copied into HLS-fMP4 for AVPlayer (VP9, MPEG-2, VC-1, AV1 on a device with no hardware decoder for it).

Not the same as unplayable: PrismCoreEngine.decide routes exactly these sources to the software path. A host that reached this by building a PrismCoreSession directly should ask the engine instead of giving up.

case videoCodecUnplayable(codecName: String)

The video codec cannot ride the fMP4 pipeline and this FFmpeg build has no decoder for it either — nothing in this engine can play it. Only the router proves this, because only the router consults SoftwareDecoderAvailability.

case startupBudgetExpired

The startup budget ran out with no playable playlist, and the remux left no error of its own — the source is being read, just not fast enough (a starving origin, a Matroska without Cues on a slow share).

A startup that timed out because of something nameable does not land here: classify(_:) unwraps the underlying error first, so a 403 during startup is .originRefused.

case masterRejectedByPlayer(underlying: any Error)

AVPlayer refused the master playlist we served (see MasterRejection for the three codes and why they are what they are). The source was never the problem; the remedy is makeMasterRejectionFallbackSession(), not another engine.

case workDirectoryOutOfSpace(underlying: (any Error)?)

A write into the session's work directory failed for want of space.

case ffmpeg(code: Int32, operation: String, message: String)

A libav* call failed with a code we have no honest mapping for. The raw code and FFmpeg's own message are kept rather than flattened into .unknown, because they are what a bug report needs — and because the next real mapping will be found by reading these.

case unknown(underlying: any Error)

Something failed and the engine cannot say what. Honest, and on purpose: a misclassification costs a host a wrong remedy, .unknown costs it a generic one.

Instance properties

var retryability: Retryability { get }

No documentation comment in the source.

var description: String { get }

No documentation comment in the source.

Type methods

static func classify(_ error: any Error) -> PrismCoreError

Classify any error this engine (or the host's AVPlayer) produced.

Recursive, because the interesting cause is routinely two wrappers deep: SessionError.startupTimedOut(underlying: SourceProbe.Failure .openFailed(FFmpegError(…))) is the common shape, not an exotic one.

Enumeration

PrismCoreError.Retryability

enum Retryability

Whether an identical attempt, later, could plausibly succeed.

Three-valued rather than Bool because for some failures the truthful answer is that this engine does not know, and a Bool would have to invent one. Each verdict is justified where it is returned.

Cases

case retryable

No documentation comment in the source.

case permanent

No documentation comment in the source.

case unknown

No documentation comment in the source.

Generated from the public symbols of PrismCore 3.5.4. All types