The event contract
The normalized, engine-agnostic events analytics and host code bind to.
onEvent receives a discriminated union — the normalized event contract. Consumers
— analytics (Nielsen / Chartbeat / GA) and host-page coordination — bind to these
events, never to raw Shaka or IMA events, so the Engine can change without touching
consumers (ADR 0005/0006).
Playback
type | payload | meaning |
|---|---|---|
ready | { isLive } | stream loaded and ready to play |
play | — | playback requested (may still be buffering) |
playing | — | media is actually advancing |
paused | — | playback paused |
error | { error } | error.fatal distinguishes terminal from recoverable |
Ads
DAI stitches ad pods into the live stream server-side; the window between
adbreakstart and adbreakend is the adplaying state (controls locked, ad overlay
shown).
type | payload | meaning |
|---|---|---|
adbreakstart / adbreakend | — | an ad break (pod) started / ended |
adstart | { ad } | an individual ad started (position, count, duration when known) |
adquartile | { quartile } | first / midpoint / third / complete — used for beacons |
adskip | — | a skippable ad (CSAI pre-roll) was skipped by the viewer |
adfinish | — | an individual ad finished |
aderror | { error } | an ad/SDK error; playback fails open to content |
Captions
type | payload | meaning |
|---|---|---|
texttrackschange | { tracks } | the set of available caption/subtitle tracks changed |
cuechange | { cues } | the active caption cues changed |
Narrowing
import type {
PlayerEvent,
PlayerEventOf,
} from "@grahamdigital/livestream-player";
function onEvent(event: PlayerEvent) {
if (event.type === "adstart") {
// event is PlayerEventOf<"adstart"> — `event.ad` is available
beacon("ad_start", { position: event.ad.position });
}
}Errors
Every error / aderror payload is a normalized PlayerError:
interface PlayerError {
code?: string | number; // engine-specific, when available
category?: string | number; // coarse: network / media / manifest
message: string; // human-readable, non-localized
fatal: boolean; // true when playback needs a reload
cause?: unknown; // underlying engine error — NOT stable contract
}Telemetry
onTelemetry is a separate, minimal operational sink — fatal errors and startup
failures only (full QoS is deferred, ADR 0006):
interface TelemetryEvent {
type: "startup_failure" | "fatal_error";
error: PlayerError;
reloadAttempt: number; // 1-based silent-reload attempt (0 if none scheduled)
}Trigger it in the demo with Simulate outage.