// The player: an HLS address, played by the platform's player through the WAI native sink. The // sink verifies each playlist against its receipt and each object against the hash its name // states, withholds what does not verify, signs an acknowledgement of everything received, and, // when the session ends, a bundle the stream's owner verifies. import AVKit import SwiftUI import WaiSink struct PlayerApp: App { var body: some Scene { WindowGroup("WAI player") { PlayerView() } } } struct PlayerView: View { @State private var address = "http://127.0.0.1:8080/package/hls/classic/floor-v.m3u8" @State private var player: AVPlayer? @State private var session: WaiPlayerSession? @State private var status = "Give an HLS address and press Play." var body: some View { VStack(alignment: .leading, spacing: 12) { HStack { TextField("HLS address", text: $address).textFieldStyle(.roundedBorder) Button("Play", action: play) } VideoPlayer(player: player).frame(minWidth: 480, minHeight: 270) Text(status).font(.callout).foregroundStyle(.secondary) } .padding() } private func play() { guard let url = URL(string: address) else { status = "Not an address."; return } do { // The owner is the key of the collector the bundle is meant for; this player keeps it. let config = WaiSink.Config(channel: "my-channel", owner: String(repeating: "0", count: 64)) let s = try WaiPlayerSession(url: url, config: config, attention: WaiFixedAttention()) s.onEnd = { bundle, ended in status = "Ended (\(ended.rawValue)): a signed bundle of \(bundle.count) bytes." } s.start() session = s player = s.player status = "Playing through the sink." } catch { status = "The sink refused: \(error)" } } }