/** * Bridge for communicating between a Livery Video Player and the interactive layer page shown within that. * * Exports: * * - Class {@link InteractiveBridge} enables a Livery interactive layer element or page to communicate with * the surrounding Livery Player * - Class {@link AbstractPlayerBridge} is used by LiveryPlayer for the `PlayerBridge` implementation * (in the past: {@link LiveryBridge}) * - Type {@link LiveryBridgeTarget} for the AbstractPlayerBridge (and LiveryBridge) constructor * - Class {@link MockPlayerBridge} is a player bridge that returns mock data for testing * - Element {@link LiveryBridgeLog} logs messages posted to specified bridge or the window * - Element {@link LiveryBridgeMock} mocks a LiveryPlayer with an interactive child element or iframe for testing * - Element {@link LiveryBridgeInteractive} is an interactive element that enables testing all interactive commands * - Variable {@link version} specifies the version of this package * - Schema types: * {@link AuthClaims}, {@link Config}, {@link DisplayMode}, {@link Features}, {@link InteractivePlayerOptions}, * {@link Orientation}, {@link PlaybackDetails}, {@link PlaybackMode}, {@link PlaybackState}, {@link Qualities}, * {@link Quality}, {@link StreamPhase}, {@link UserFeedback} and {@link Volume}. * - Schema validators: validateAuthClaims. * * **Note:** When using the UMD bundle, the exports can be found as properties of `livery` in the global namespace, * e.g: `livery.version`. * * @packageDocumentation */ import { CSSResult } from 'lit'; import { LitElement } from 'lit'; import { PropertyValues } from 'lit'; import { TemplateResult } from 'lit-html'; /** * Abstract player bridge class which implements part of the player side API based on browser logic * and defines abstract methods to be implemented to complete support for all InteractiveBridge commands. */ export declare abstract class AbstractPlayerBridge extends LiveryBridge { protected abstract config: Config; protected portraitQuery: MediaQueryList; /** * Authenticate user in interactive layer with specified token or claims, * or logout the user by passing an `undefined` value. * * @param tokenOrClaims - JWT token string or claims to authenticate with or undefined to logout */ authenticate(tokenOrClaims?: AuthClaims | string): Promise; /** * Returns promise of options from interactive layer for the player. * Or default options if the interactive bridge doesn't support this/these yet. * * Note: In the future this could also pass options from player to the interactive layer. * * @deprecated In the next major version options passing should be integrated into the LiveryBridge handshake. */ options(): Promise; /** * Register `handler` function to be called with `arg` and `listener` when `sendPlayerCommand()` is called * from the interactive layer side with matching `name`. */ registerPlayerCommand(name: string, handler: (arg: unknown, listener: (value: unknown) => void) => unknown): void; /** * Returns promise of value returned by the interactive layer's custom command handler with matching `name` that is passed `arg`. * Any `handler` `listener` calls will subsequently also be bridged to this `listener` callback. */ sendInteractiveCommand(name: string, arg?: unknown, listener?: (value: unknown) => void): Promise; /** * Unregister custom interactive command by name. */ unregisterPlayerCommand(name: string): void; protected abstract getEndpointId(): string; protected abstract getFeatures(): Features; protected abstract getPlayback(): PlaybackDetails; protected abstract getPlayerVersion(): string; protected abstract getStreamId(): string; protected handleCommand(name: string, arg: unknown, listener: (value: unknown) => void): unknown; protected abstract pause(): void; protected abstract play(): void; protected abstract reload(): void; protected abstract seek(position: number): void; protected abstract selectQuality(index: number): void; protected abstract setDisplay(display: DisplayMode): void; protected abstract setMuted(muted: boolean): void; protected abstract setVolume(volume: number): void; protected abstract submitUserFeedback(value: UserFeedback): void; protected abstract subscribeConfig(listener: (value: Config) => void): Config; protected abstract subscribeDisplay(listener: (display: DisplayMode) => void): DisplayMode; protected abstract subscribeError(listener: (error: string | undefined) => void): string | undefined; protected abstract subscribeMode(listener: (mode: PlaybackMode) => void): PlaybackMode; protected abstract subscribePlaybackState(listener: (playbackState: PlaybackState) => void): PlaybackState; protected abstract subscribeQualities(listener: (qualities: Qualities) => void): Qualities; protected abstract subscribeVolume(listener: (volume: Volume) => void): Volume; /** * @deprecated Instead use {@link subscribeConfig}.customerId */ /** * @deprecated Instead use {@link getPlayback}.latency */ /** * @deprecated Instead compare {@link subscribeDisplay} value to 'FULLSCREEN' */ /** * @deprecated Will be removed in the next major version. */ /** * @deprecated Instead use {@link subscribeQualities}.active to get the active quality index * and use the index to get the active quality label from {@link subscribQualities}.list */ /** * @deprecated Instead use {@link subscribeConfig}.streamPhase */ } /** * ---------------------------------------------------------------- * Objects * ---------------------------------------------------------------- */ /** * Authentication claims. * * Of these claims the following are externally defined standard OpenID: * `sub, updated_at, phone_number_verified, email_verified` * * And these are user editable standard OpenID: * `given_name, family_name, middle_name, preferred_username, picture, email, gender, birthdate, locale, phone_number` * * And these are Livery specific: * `verified, minimum_age` * * For detailed descriptions see: * https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims */ export declare interface AuthClaims { /** Unknown claims. */ [claim: string]: unknown; /** End-User's birthday, represented as an ISO 8601-1 [ISO8601‑1] YYYY-MM-DD format. */ birthdate?: string; /** Custom Livery user property 1. */ custom1?: string; /** Custom Livery user property 2. */ custom2?: string; /** Custom Livery user property 3. */ custom3?: string; /** Custom Livery user property 4. */ custom4?: string; /** Custom Livery user property 5. */ custom5?: string; /** End-User's preferred e-mail address. */ email?: string; /** True if the End-User's e-mail address has been verified; otherwise false. */ email_verified?: boolean; /** Surname(s) or last name(s) of the End-User. */ family_name?: string; /** End-User's gender. */ gender?: string; /** Given name(s) or first name(s) of the End-User. */ given_name?: string; /** End-User's locale, represented as a BCP47 [RFC5646] language tag. */ locale?: string; /** Middle name(s) of the End-User. */ middle_name?: string; /** Age as entered by user for minimum age consideration. */ minimum_age?: number; /** End-User's preferred telephone number. */ phone_number?: string; /** True if the End-User's phone number has been verified; otherwise false. */ phone_number_verified?: boolean; /** URL of the End-User's profile picture. */ picture?: string; /** Shorthand name by which the End-User wishes to be referred to at the RP, such as janedoe or j.doe. */ preferred_username?: string; /** Subject - Identifier for the End-User at the Issuer. */ sub?: string; /** Time the End-User's information was last updated as number of seconds from 1970-01-01T00:00:00Z. */ updated_at?: number; /** True if the user is verified, usually by email or phone number; otherwise false. */ verified?: boolean; } /** * Public part of Livery stream config. */ export declare interface Config { /** Registry of controls that should be shown to the user. */ controls: { /** Enable toggling AirPlay and/or Chromecast display. */ cast: boolean; /** Enable submitting user feedback. */ contact: boolean; /** Enable error feedback and recovery controls. */ error: boolean; /** Enable toggling fullscreen display. */ fullscreen: boolean; /** Enable muting and unmuting audio. */ mute: boolean; /** Enable toggling picture-in-picture display. */ pip: boolean; /** Enable toggling play/pause. */ play: boolean; /** Enable quality selection. */ quality: boolean; /** Enable seeking through the stream. */ scrubber: boolean; }; /** Livery customer ID. */ customerId: string; /** Livery stream phase, i.e: PRE/LIVE/POST before/while/after streaming to viewers. */ streamPhase: StreamPhase; /** Array of [unixTimestamp, streamPhase] tuples listing the times at which those phases started. */ streamPhases: [number, StreamPhase][]; /** Livery tenant ID. */ tenantId: string; } /** * ---------------------------------------------------------------- * String Unions * ---------------------------------------------------------------- */ /** * Mode of display for player and/or video, i.e: * * - `'DEFAULT'` for default display in the web page * - `'FULLSCREEN'` for fullscreen display * - `'PIP'` for picture-in-picture display of the video (the interactive layer remains in the page) * - `'AIRPLAY'` for Airplay display of the video (not yet supported by web player) * - `'CHROMECAST'` for Chromecast display of the video (not yet supported by web player) */ export declare type DisplayMode = 'AIRPLAY' | 'CHROMECAST' | 'DEFAULT' | 'FULLSCREEN' | 'PIP'; /** * Registry of features supported by the player in general and under given circumstances. */ export declare interface Features { airplay: boolean; chromecast: boolean; contact: boolean; fullscreen: boolean; pip: boolean; scrubber: boolean; volume: boolean; } /** * Can be used by a Livery interactive layer element or page to communicate with the surrounding Livery Player. * * @example * ```js * import { InteractiveBridge } from '@liveryvideo/interactive-bridge'; * * // The `playerBridge` will be provided to you as interactive element * // Or, as interactive page, to prevent cross site security issues: * // https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#security_concerns * // replace `'*'` by the origin of the page that the player is expected to be on * const bridge = new InteractiveBridge(playerBridge || '*'); * * bridge.getAppName().then(appName => window.alert(`appName: ${appName}`)); * ``` */ export declare class InteractiveBridge extends LiveryBridge { /** * Constructs `InteractiveBridge` with specified `target` player bridge * or with `window.parent` as target window and with specified string as origin. * * @param target - Player bridge or window origin to target * @param options - Options for this bridge and {@link InteractivePlayerOptions} */ constructor(target: AbstractPlayerBridge | string, options?: { /** True if default player controls should be disabled to use custom controls instead, false otherwise. */ controlsDisabled?: boolean; /** * Handles authentication data coming from the player. * * @param tokenOrClaims - JWT token string or claims to authenticate with or undefined to logout */ handleAuth?: (tokenOrClaims?: AuthClaims | string) => void; }); /** * Returns promise of player application name. */ getAppName(): Promise; /** * Returns promise of player customer id. * * @deprecated Instead use {@link subscribeConfig}.customerId */ getCustomerId(): Promise; /** * Returns promise of player Pinpoint analytics endpoint id. */ getEndpointId(): Promise; /** * Returns promise of a registry of features supported by the player in general and under given circumstances. */ getFeatures(): Promise; /** * Returns promise of current player latency in seconds. * * @deprecated Instead use {@link getPlayback}.latency */ getLatency(): Promise; /** * Returns promise of an object of key-value string parameters from player. * * Android and iOS players will call a callback and pass on the returned values. * * The web player will return all 'livery_' prefixed query parameters with: * * - The prefix stripped from the names (snake_case will not be converted to camelCase) * - Parameter names and values URL decoded * - Empty string (not `null`) values for parameters without a value * - Only the first value of a repeated parameter (no multiple value array support) * * So given location.search: `'?foo&livery_foo%3Abar=hey+you&livery_no_val&livery_multi=1&livery_multi=2'` * this will return: `{ 'foo:bar': 'hey you', no_val: '', multi: '1' }`. */ getLiveryParams(): Promise>; /** * Returns promise of current playback details, i.e: values that are continuously changing. */ getPlayback(): Promise; /** * Returns promise of player version. */ getPlayerVersion(): Promise; /** * Returns promise of player stream id. */ getStreamId(): Promise; /** * Pause playback. */ pause(): Promise; /** * Attempt to start or resume playback. * * Can fail if not allowed by the browser, e.g: when not called directly from a click event listener. * In that case it can fall back to muted playback, changing {@link subscribeVolume}.muted to true. * Or if that also fails then {@link subscribePaused} will remain true. */ play(): Promise; /** * Register `handler` function to be called with `arg` and `listener` when `sendCustomCommand()` is called on * other side with matching `name`. * * @deprecated Instead use {@link registerInteractiveCommand} */ registerCustomCommand(name: string, handler: (arg: unknown, listener: (value: unknown) => void) => unknown): void; /** * Register `handler` function to be called with `arg` and `listener` when `sendInteractiveCommand()` is called * from the player side with matching `name`. * * @param name - Custom command name to listen to * @param handler - Function to handle those commands and whose value to return to it */ registerInteractiveCommand(name: string, handler: (arg: unknown, listener: (value: unknown) => void) => unknown): void; /** * Reload player, e.g: to try to recover from an error. */ reload(): Promise; /** * Seek to specified `position` in seconds since start of stream/VOD. * * Where `position` needs to be within a `'LIVE'` interval of {@link subscribeConfig}.streamPhases * and the {@link getPlayback}.duration. * * Requires: {@link getFeatures}.scrubber. * * @param position - Position in seconds since start of stream/VOD to seek to */ seek(position: number): Promise; /** * Select quality at specified index of {@link subscribeQualities}.list or -1 to use ABR. * * @param index - Index of quality to select * @throws Error "Player unconfigured" when config has not been loaded yet * @throws Error "Qualities undefined" when stream qualities have not been loaded yet * @throws Error "Cannot select quality when a quality is forced" * @throws RangeError when index is not -1 or a valid quality index */ selectQuality(index: number): Promise; /** * Returns promise of value returned by other side's custom command handler with matching `name` that is passed `arg`. * Any `handler` `listener` calls will subsequently also be bridged to this `listener` callback. * * @deprecated Instead use {@link sendPlayerCommand} */ sendCustomCommand(name: string, arg?: unknown, listener?: (value: unknown) => void): Promise; /** * Returns promise of value returned by the player's custom command handler with matching `name` that is passed `arg`. * Any `handler` `listener` calls will subsequently also be bridged to this `listener` callback. * * @param name - Name of custom command to send * @param arg - Optional argument to custom command to send * @param listener - Optional listener function to be called with custom command handler listener call values */ sendPlayerCommand(name: string, arg?: unknown, listener?: (value: unknown) => void): Promise; /** * Attempt to change display mode to specified value. * * Can reject if not allowed by the browser, e.g: when not called directly from a click event listener. * * Requires related feature, i.e: {@link getFeatures}.airplay, chromecast or fullscreen. * * @param display - Display mode to attempt to change to */ setDisplay(display: DisplayMode): Promise; /** * Attempt to change `muted` state to specified value. * * Unmuting can fail if not allowed by the browser, e.g: when not called directly from a click event listener. * The specified state is kept track of by the player though and respected on reload when possible. * Look at {@link subscribeVolume}.muted state to track actual unmuting. * * @param muted - Muted state to attempt to change to */ setMuted(muted: boolean): Promise; /** * Change `volume` to specified value. * * When a player starts unmuted at volume `0` and this is changed to a higher volume later, * that can be disallowed by the browser, e.g: when not called directly from a click event listener. * In that case the player will fall back to changing {@link subscribeVolume}.muted to `true` * to allow the volume change to persist. * * Requires: {@link getFeatures}.volume. * * @param volume - Volume, between 0 and 1, to change to */ setVolume(volume: number): Promise; /** * Submit user feedback. * * Requires: {@link getFeatures}.contact. * * @param feedback - User feedback to submit */ submitUserFeedback(feedback: UserFeedback): Promise; /** * Returns promise of Livery stream config * and calls back `listener` with server side updates or when streamId is changed. * * @param listener - Listener to call when value is changed */ subscribeConfig(listener: (value: Config) => void): Promise; /** * Returns promise of current display mode * and calls back `listener` with any subsequent display mode changes. * * @param listener - Listener to call when value is changed */ subscribeDisplay(listener: (value: DisplayMode) => void): Promise; /** * Returns promise of current player error message or undefined * and calls back `listener` with any subsequent errors. * * @param listener - Listener to call when value is changed */ subscribeError(listener: (value: string | undefined) => void): Promise; /** * Returns promise of current player fullscreen state * and calls back `listener` with any subsequent state changes. * * @deprecated Instead use {@link subscribeDisplay}.display value "FULLSCREEN" */ subscribeFullscreen(listener: (value: boolean) => void): Promise; /** * Returns promise of current mode of playback, e.g. how to buffer, sync, adapt quality, manage stalls, etc. * and calls back `listener` with any subsequent mode changes. * * @param listener - Listener to call when value is changed */ subscribeMode(listener: (mode: PlaybackMode) => void): Promise; /** * Returns promise of current player window orientation (`'landscape' \| 'portrait'`) * and calls back `listener` with any subsequent orientations. * * @deprecated Will be removed in the next major version. */ subscribeOrientation(listener: (value: Orientation) => void): Promise; /** * Returns promise of current `paused` state and calls back `listener` with any subsequent `paused` state updates. * * Where `paused` is true if `playbackState` is `'PAUSED'` or `'ENDED'`. * I.e: Not playing as intended. * * @param listener - Listener to call when value is changed */ subscribePaused(listener: (value: boolean) => void): Promise; /** * Returns promise of current player playback state * and calls back `listener` with any subsequent state updates. * * @param listener - Listener to call when value is changed */ subscribePlaybackState(listener: (value: PlaybackState) => void): Promise; /** * Returns promise of current `playing` state and calls back `listener` with any subsequent `playing` state updates. * * Where `playing` is true if `playbackState` is `'PLAYING'`, `'FAST_FORWARD'`, `'SLOW_MO'` or `'REWIND'`. * I.e: Playing as intended. * * @param listener - Listener to call when value is changed */ subscribePlaying(listener: (value: boolean) => void): Promise; /** * Returns promise of current player stream qualities * and calls back `listener` with any subsequent qualities changes. * * @param listener - Listener to call when value is changed */ subscribeQualities(listener: (value: Qualities) => void): Promise; /** * Returns promise of current player stream quality * and calls back `listener` with any subsequent quality changes. * * @deprecated Instead use {@link subscribeQualities}.active * * @param listener - Listener to call when value is changed */ subscribeQuality(listener: (value: string) => void): Promise; /** * Returns promise of current `stalled` state and calls back `listener` with any subsequent `stalled` state updates. * * Where `stalled` is true if `playbackState` is `'BUFFERING'` or `'SEEKING'`. * I.e: Not playing, but trying to. * * @param listener - Listener to call when value is changed */ subscribeStalled(listener: (value: boolean) => void): Promise; /** * Returns promise of current player stream phase (`'PRE' \| 'LIVE' \| 'POST'`) * and calls back `listener` with any subsequent phases. * * @deprecated Instead use {@link subscribeConfig}.streamPhase */ subscribeStreamPhase(listener: (phase: StreamPhase) => void): Promise; /** * Returns promise of current player volume state * and calls back `listener` with any subsequent volume changes. * * @param listener - Listener to call when value is changed */ subscribeVolume(listener: (volume: Volume) => void): Promise; /** * Unregister custom command by name. * * @deprecated Instead use {@link unregisterInteractiveCommand} */ unregisterCustomCommand(name: string): void; /** * Unregister custom interactive command by name. * * @param name - Name of custom command handler to unregister */ unregisterInteractiveCommand(name: string): void; protected handleCommand(name: string, arg: unknown, listener: (value: unknown) => void): unknown; } /** * Options from interactive layer for the player. */ export declare interface InteractivePlayerOptions { /** True if default player controls should be disabled to use custom controls instead, false otherwise. */ controlsDisabled: boolean; } /** * Base Livery bridge class, to be extended by {@link InteractiveBridge} and {@link AbstractPlayerBridge}. */ export declare class LiveryBridge { static readonly isLiveryBridge = true; /** * Constructs a LiveryBridge. * * Target can be either undefined, a LiveryBridge instance or a window and origin. * If undefined this waits for the other bridge to be passed this instance * and for that in turn to pass it's reference here. * * @param target - LiveryBridge target */ constructor(target?: LiveryBridgeTarget); protected handleCommand(name: string, _arg: unknown, _listener: (value: unknown) => void): unknown; /** * Register `handler` function to be called with `arg` and `listener` when `sendCustomCommand()` is called on * other side with matching `name`. */ protected registerCustomCommand(name: string, handler: (arg: unknown, listener: (value: unknown) => void) => unknown): void; protected sendCommand(name: string, arg?: unknown, listener?: (value: unknown) => void, custom?: boolean): Promise; /** * Returns promise of value returned by other side's custom command handler with matching `name` that is passed `arg`. * Any `handler` `listener` calls will subsequently also be bridged to this `listener` callback. */ protected sendCustomCommand(name: string, arg?: unknown, listener?: (value: unknown) => void): Promise; /** * Unregister custom command by name. */ protected unregisterCustomCommand(name: string): void; } /** * Test element defined as `` which can be used as Livery Interactive element * for testing purposes. * * This dispatches a 'load' event once it's loaded and `interactiveBridge` has been assigned. * * @group Elements * @noInheritDoc * @example * ```js * const interactive = document.createElement('livery-bridge-interactive'); * interactive.playerBridge = new MockPlayerBridge(); * interactive.region = 'eu'; * interactive.tenantId = 'abc123'; * document.body.appendChild(interactive); * ``` */ export declare class LiveryBridgeInteractive extends LitElement { static readonly styles: CSSResult; static readonly version: string; auth: string; /** * InteractiveBridge instance created by this element on first DOM connect. */ interactiveBridge?: InteractiveBridge; /** * `PlayerBridge` to use as target for `interactiveBridge`. * * Note: Only effective when defined before first DOM connect. * * If `undefined` this will default to using `parent` as `target.window` and `'*'` as `target.origin`. * * Note: Without `origin` restriction don't send sensitive information or trust responses, * this is only meant to be used for testing purposes. */ playerBridge?: AbstractPlayerBridge; /** * Region of interactive server that interactive element should connect to. * @group Attributes * @defaultValue null */ region: null | string; /** * Id of tenant that interactive element should use on server. * @group Attributes * @defaultValue null */ tenantId: null | string; connectedCallback(): void; render(): TemplateResult<1>; } /** * Element defined as `` which logs messages posted to specified {@link bridge} or the window. * * @group Elements * @noInheritDoc * @example * ```html * * ``` */ export declare class LiveryBridgeLog extends LitElement { static readonly styles: CSSResult; static readonly version: string; /** * Bridge to spy on. * * If undefined this will instead just listen to messages posted to this window. * * Note: This needs to be defined before this element is connected to DOM. */ bridge?: LiveryBridge; /** * Maximum number of messages to display. * @group Attributes * @defaultValue 10 */ maxMessages: number; connectedCallback(): void; disconnectedCallback(): void; firstUpdated(changedProperties: PropertyValues): void; render(): TemplateResult<1>; } /** * Test element defined as `` which creates a `MockPlayerBridge` * to be used by a Livery Interactive element that should be passed as a child. * * Alternatively pass an `