import Foundation /// Welcher Engine die Wiedergabe übernimmt. public enum PlaybackEngineKind: String, Sendable, Equatable, Codable { /// Der Systemplayer. Bringt Bild-in-Bild, AirPlay und die Steuerung im /// Sperrbildschirm mit — deshalb hat er immer Vorrang, wenn er kann. case avPlayer /// VLCKit. Spielt praktisch jedes Format, kann dafür kein Bild-in-Bild. case vlc } /// Wie ein Titel abgespielt werden soll. public struct PlaybackDecision: Sendable, Equatable { public enum Method: Sendable, Equatable { /// Die Datei wird unverändert übertragen und lokal dekodiert. case directPlay(engine: PlaybackEngineKind) /// Der Server rechnet um. Ab Phase 2; `maximumBitrate` in Kilobit. case transcode(maximumBitrate: Int?) } /// Warum es so entschieden wurde. /// /// Wandert in die technischen Infos auf der Detailseite und ins Protokoll. /// Ohne diese Begründung ist „warum ruckelt das" nicht zu beantworten. public enum Rationale: Sendable, Equatable { case nativelySupported case containerUnsupported(String) case videoCodecUnsupported(String) case audioCodecUnsupported(String) /// Der Server hat die Datei noch nicht analysiert. case streamsUnknown case bitrateExceedsLimit(mediaBitrate: Int, limit: Int) /// Transcoding wäre passender, ist aber (noch) nicht verfügbar. case transcodingUnavailable /// Im Player ausdrücklich eine Stufe gewählt. case qualityChosen } public let method: Method public let rationale: [Rationale] public init(method: Method, rationale: [Rationale]) { self.method = method self.rationale = rationale } public var engine: PlaybackEngineKind? { switch method { case .directPlay(let engine): engine // Der Transcoder liefert HLS — das ist genau die Kost, für die // AVPlayer gebaut ist, inklusive automatischem Bitratenwechsel. case .transcode: .avPlayer } } public var isDirectPlay: Bool { if case .directPlay = method { return true } return false } }