Skip to content

JavaScript Player - Documentation

Note

This page has been updated for the v1 release of the player. If you are using an older version, go here instead, and if you are just learning about the new major release, you may want to see the release notes and migration guide.

The Red Bee Media Managed OTT JavaScript SDK is our playback client SDK for platforms supporting Javascript and HTML5 video. It acts as a middle layer between your web application, the HTML5 video player APIs and the Red Bee Platform, so you don't have to focus on complicated and time consuming details like device compatibility, authentication, analytics and more.

Installation

We recommend installing the player using npm or yarn:

npm install @redbeemedia/javascript-player or yarn add @redbeemedia/javascript-player

If you prefer using a CDN or downloading the files to be included in your project, you may include the files from the jsdelivr cdn or similar alternatives. Note that using this method, all exports is set on the redBeeMedia object. So instead of just RedBeePlayer you'll have to call redBeeMedia.RedBeePlayer

From jsdelivr

<script src="https://cdn.jsdelivr.net/npm/@redbeemedia/javascript-player@latest/dist/redbee-player.min.js"></script>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@redbeemedia/javascript-player@latest/style.css">

Supported Platforms

The player supports the latest two major versions of Google Chrome, Microsoft Edge, Apple Safari & Mozilla Firefox on both desktop & mobile. For SmartTV we support LG WebOS 4.0+ & Samsung Tizen 3.0+.

The player requires modern browser and javascript APIs, so we recommend using the following polyfills in your web app for full compatability:

You may use any polyfill solution you want as long as the resulting browser environment match the above polyfills.

LG WebOS

The player requires the WebOSTV.js library needs to be loaded before playback.

Samsung Tizen

The player requires the WebAPI script to be loaded before playback.

The player requires the following privileges to be set

Usage

The player comes with an easy to use default configuration, but can also be customized and tailored to very complex use cases, should you need to.

Getting Started

This example will cover most of your needs, and is a great base to start at.

Set up the wrapper element in which the player will render

<div id="video-wrapper"></div>
import { RedBeePlayer } from "@redbeemedia/javascript-player";
import "@redbeemedia/javascript-player/style.css";

const wrapperElement = document.querySelector("div#video-wrapper");

const playerOptions = {
  customer: "DemoCustomer",
  businessUnit: "DemoBusinessUnit",
  username: "MyEndUser",
  password: "MyPassword123",
  exposureBaseUrl: "", // Provided by Red Bee Media
  wrapperElement: wrapperElement,
}

const player = new RedBeePlayer({ player: playerOptions });
player.once(PlayerEvents.LOADED, () => {
  // player is loaded
});
player.on(PlayerEvents.ERROR, () => {
  // player has encountered an error
});
player.load("e720d1da-0915-411b-807c-3e83f451bbb7_29C72F");

The player emits useful events that you can listen to, such as when the player has loaded, the user pauses, changes the subtitle track and much more.

import { PlayerEvents } from "@redbeemedia/javascript-player";

// Log all events
player.onAll(({ event, data }) => {
  const eventName = Object.keys(PlayerEvents).find((key) => PlayerEvents[key] === event);
  console.log(`[Red Bee Player] ${eventName}`, data);
});

See (see events for more details.

Authentication

If you just need to get a sessionToken for other authorization required scenariros (such as personalized calls against the Exposure API) there is an exposed service to be used. The ExposureService.

First, get an instance of the Exposure service set up.

import { ExposureService } from "@redbeemedia/javascript-player";

const exposureService = new ExposureService({
  customer,
  businessUnit,
  exposureBaseUrl
});

Then authenticate to get the session token.

const { sessionToken, deviceId } = await exposureService.authenticate({
  username,
  password
});

If you want to create an anonymous session your can either call the authentication method without username and password

const { sessionToken, deviceId } = await exposureService.authenticate();

Or you can directly call the method authenticateAnonymous

const { sessionToken, deviceId } = await exposureService.authenticateAnonymous();

Options

There are three different option categories player, skin and analytics. They are provided as separate objects when initializing the player.

new RedBeePlayer({
  player: { /* player options here */}
  skin: { /* skin options here */}
  analytics: { /* analytics options here */}
})

player

Required

  • customer
  • businessUnit
  • exposureBaseUrl
  • wrapperElement

For playback from the Red Bee platform you will need either

  • sessionToken

or

  • username
  • password

If you initiate the player with a sessionToken instead of credentials, you can choose to provide a deviceId to align the analytics session with your definition of the user's device in other contexts of your application. This will otherwise be pulled from the token or auto generated.

If you initiate the player without credentials, nor sessionToken, the SDK will automatically try to do an anonymous login towards the platform.

Optional

  • autoplay, default true
  • muted, default false
  • preferredFormats, default ["hls", "dash"]
  • debug, default false, log analytics into the console instead of sending to the backend.
  • locale, the language to use for metadata when casting & for the browser MediaSession.
  • castAppId, defaults to the default unbranded RBM receiver.
  • disableCast, default false
  • disableAirPlay, default false
  • fullscreenElement, the element that goes to fullscreen when pressing the fullscreen button, defaults to wrapperElement. Usable when you want to apply further elements in the full screen experience.
  • maxResolution. Use this to filter out specific variants. Note that this requires a backend configuration for your organization, reach out to your Red Bee representative for help.
  • metadataURIs, For MPEG-DASH streams, this is a list with the EventStream schemeIdURIs. Use this to expose one or more timed metadata events when present.
  • customShakaConfiguration, see shaka api documentation
  • customHlsJsConfiguration, see hls.js api documentation
  • customDashJSConfiguration, see dash.js api documentation

skin

Our basic skin creates a great default experience for everything from VOD to Live and Channels. It also brings some functionality in terms of showing Metadata related to the ongoing asset as well as possibility to AirPlay or Cast your content to big screen.

By default, the skin also sets up keyboard shortcuts to allow users to control the player using their keyboard.

  • Spacebar: Toggle play/pause
  • Right Arrow: Forward 15 seconds
  • Left arrow: Rewind 15 seconds
  • m: Toggle mute/unmute
  • f: Toggle fullscreen/window

If you want to use it there are some additional settings available to adjust its behavior.

Example

const redbeePlayer = new RedBeePlayer({
  player: { ... },
  skin: {
    disabled: true 
  }
});

Options

  • disabled, default false. Set to true to disable the default skin.
  • keyboardShortcuts, default true. Set to false to disable the keyboard shortcuts.
  • hideControlsTimer, default 2500. How many milliseconds until the skin hides when there's no activity.
  • showMetadata, default true. Whether to show the image, title, duration and description for the ongoing asset.
  • showQualitySelector, default true. Whether to show the quality selector or just go by auto quality selection.
  • showJumpButtons, default true. Whether to show buttons that allows the end user to jump back and forth 30 seconds in the stream.
  • showSubtitlesToggleButton, default false. Whether to show a subtitle toggle button. NOTE! This is not currently supported if you have multiple text tracks.
  • allowPictureInPicture, default true.
  • showWallClock, to show wall clock rather than zero based when applicable data is available. Will default to the client's timezone.
  • timeZone, to have a set timezone for the wall clock timestamp to be shown. (The tz database name standard, e.g. Europe/London)

analytics

Analytics will automatically connect to the Red Bee Platform to send Analytics according to the backend expectation enabling you as a customer to dive deep into the data of your end user's consumption behavior.

Options

  • disabled, default false. Set to true to disable analytics. NOTE! This is not recommended and should only be done if you understand the consequences.
  • baseUrl, default set to the value of exposureBaseUrl set as player options. For some big events Red Bee will distribute a custom analytics base url for scaling purpose.
  • appName. To be used when you have multiple applications that will be reported to the same analytics bucket.

Load method

The load method starts loading the media source(s).

It can be invoked in a number of ways:

player.load("e720d1da-0915-411b-807c-3e83f451bbb7_29C72F"); // asset id
player.load("external:e720d1da-0915-411b-807c-3e83f451bbb7"); // external asset id
player.load("https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd"); // external manifest url

// Load with additional options
player.load({
  source: "e720d1da-0915-411b-807c-3e83f451bbb7_29C72F",
  poster: "https://example.com/poster.jpg",
  audioOnly: true, 
});

Options

  • source, the asset id or manifest or media url.
  • startTime, time (in seconds) for the player to start from. For VOD assets, the default behavior when not passing startTime is that the player will continue where the user left off. If you do not want this, set startTime to 0. For live, passing any startTime value makes the player start from this offset time from the start of the stream, instead of starting from the live edge. startTime is applied separate from the manifest start property (you can use both).
  • audioOnly, default false, - Set to true to only play the audio from the stream.
  • poster, URL for an image to show while the player is paused, stopped or during playback of audio only sources. Not normally needed as you can add a poster to the asset in our platform instead.
  • manifest ({ start?: number, end?: number }), optional start and end times (in seconds) to limit the stream to. The stream will align to segment boundaries. manifest.start is applied separate from startTime (you can use both).
  • materialProfile, name of the specific video material profile to load (usually not needed)
  • ads, default undefined, see below for details

ads

Type: { [key: string]: string }

NOTE! The typescript definitions specify number/boolean in some cases, but the player will always convert these to strings before sending them to the API

The ads object is used to pass additional ad parameters to the ad server when loading the asset. Red Bee or your ad server provider should let you know which parameters to include.

For a list of all supported ad parameters see https://exposure.api.redbee.live/docs/index.html#/entitlements/play and see the parameters marked "Used for SSAI.".

The following parameters will be derived from the player unless you override them. Only override them if you know what you are doing:

  • deviceType
  • deviceModel
  • deviceModelNumber
  • deviceMake
  • width
  • height
  • pageUrl
  • domain
  • mute
  • autoplay
  • ifa
  • ifaType
player.load({
  source: "e720d1da-0915-411b-807c-3e83f451bbb7_29C72F",
  ads: {
    consent: myCmp.getConsentString()
    limitAdTracking: myCmp.getLimitAdTracking(),
    latitude: myMapService.getLatitude(),
    longitude: myMapService.getLongitude()
  }, 
}).

Playlists

You can also give it a list (array) of either of these formats, and it will create a playlist and play them in order.

Note

If the user is casting or airplaying, when the playback for an item finishes on the device, it will continue playing the next item in the browser.

player.load([
  "13f346c0-e36a-11ed-b5ea-0242ac128462_69E84C",
  "31f8b754-e36a-11ed-b5ea-0242ac122582_E5D874b",
]);

or:

player.load([
  { source: "13f346c0-e36a-11ed-b5ea-0242ac128462_69E84C", startTime: 0 },
  { source: "31f8b754-e36a-11ed-b5ea-0242ac122582_E5D874b", startTime: 0 },
]);

Other methods

Note

All methods except load, isBrowserSupported and isPictureInPictureSupported expects the player to be loaded (and not destroyed). So you need to listen to the PlayerEvents.LOADED event (see events) before you can use them.

Contextual data

  • getPlayerInfo, player engine and its version
  • getSession, assetId, sessionToken, playSessionId, requestId etc. (see session object)
  • getAssetInfo, the asset object for the currently playing asset
  • getContractRestrictions, the restrictions that might exist for timeshift etc (see contract restrictions object)
  • getContainerElement
  • getVideoElement
  • getState see state object
  • getTimelineSpriteCues see Timeline SpriteCues

Set data or trigger behavior

  • play, starts playback
  • pause
  • setMuted true|false
  • toggleMuted
  • toggleFullscreen
  • seekTo({ time?: number, change?: number }, seek to either a specific time or a change back or forth in seconds. For Low latency content this will disable the catchup functionality.
  • seekToOffset, alias for seekTo with change
  • seekToUTC(utcTime: number), seek to a time in UTC given in milliseconds since epoch
  • seekToLive, alias for seekTo with seekable end as time argument. For Low latency content this will enable the catchup functionality if disabled by seekTo
  • setPlaybackRate
  • setAudioTrack(track: Track)
  • setSubtitleTrack(track: Track)
  • setQualityLevel(level: QualityLevel)
  • setVolume({ percentage } set volume to a percentage between 0 and 100, this is not supported on iOS devices. See Apple Developer website
  • togglePictureInPicture
  • toggleAirPlay

Get data or state

  • getSeekable
  • getCurrentTime
  • getVolume
  • getAudioTrack
  • getAudioTracks
  • getSubtitleTrack
  • getSubtitleTracks
  • getQualityLevels

  • isLive

  • isPlaying
  • isPictureInPictureSupported, check if PiP is supported, currently works on later version of Chrome & Safari
  • isPictureInPicture
  • isAirplaySupported, check if AirPlay is supported, currently works on Safari.
  • isAirplaying

  • isBrowserSupported, might be used by your site to check whether this is a user that we will be able to officially support or not.

  • destroy, kill the player

Session Object

export interface IPlayerSession {
  assetId?: string;
  initOptions?: IPlayerCoreOptions;
  sessionToken?: string;
  playSessionId?: string;
  requestId?: string;
  playbackFormat?: FormatType;
  playerEngine?: IPlayerEngine;
  autoplay?: boolean;
  locale: string;
  cdnProvider?: string;
  analyticsPostInterval?: number;
  analyticsBucket?: number;
  analyticsTag?: string;
  analyticsBaseUrl?: string;
  analyticsPercentage?: number;
}

Contract Restrictions Object

export interface IContractRestrictions {
  airplayEnabled?: boolean;
  ffEnabled?: boolean;
  maxBitrate?: number;
  maxResHeight?: number;
  minBitrate?: number;
  rwEnabled?: boolean;
  timeshiftEnabled?: boolean;
}

State Object

interface PlayerState extends IInternalPlayerState {
  isCasting: boolean;
  isCastAvailable: boolean;
  isAirPlaying: boolean;
  isAirPlayAvailable: boolean;
  contractRestrictions?: ContractRestrictions;
  contentMarkers?: MarkerPoint[];
}

interface InternalPlayerState {
  playbackState: PlaybackState;
  contentType?: ContentType | null;
  mediaType?: MediaType;
  currentTime: number;
  duration: number;
  seekable: ISeekable;
  utcCurrentTime: number;
  utcDuration: number;
  utcSeekable: ISeekable;
  currentAd?: IAdDataRepresentation | null;
  adMarkers?: IAdBlockMarker[];
  contentMarkers?: MarkerPoint[];
  volume: number;
  subtitleTrack: Track | null;
  subtitleTracks: Track[];
  audioTrack: Track | null;
  audioTracks: Track[];
  qualityLevel: QualityLevel;
  qualityLevels: QualityLevel[];
  droppedFrames: number;
  bufferingEvents: number;
  hasStarted: boolean;
  isMuted: boolean;
  isLive: boolean;
  isSeekable: boolean;
  isAtLiveEdge: boolean;
}

const PlaybackState = {
  IDLE: "idle",
  LOADING: "loading",
  PLAYING: "playing",
  PAUSED: "paused",
  BUFFERING: "buffering",
  SEEKING: "seeking",
  ENDED: "ended",
  ERROR: "error",
} as const;

const ContentType = {
  VOD: "vod",
  LIVE: "live",
  AD: "ad",
  PODCAST: "podcast",
} as const;

interface Seekable {
  start: number;
  end: number;
}

interface IAdBlockMarker {
  startTime: number;
  duration: number;
  watched: boolean;
}

interface Track {
  id: string;
  language: string;
  label: string;
}

interface QualityLevel {
  id: number;
  name?: string;
  bandwidth?: number;
  width?: number;
  height?: number;
  framerate?: number;
}

Timeline SpriteCues

The method getTimelineSpriteCues is used to get an array of SpriteCues which are objects describing a sprite within a spritesheet that represents the playing content at a specific time.

This is used to in the included skin to show thumbnails above the progressbar when seeking.

The SpriteCue object looks like this

interface ISpriteCue {
  image: string; // URL to the spritesheet image
  start: number; // The first second on the timeline that this SpriteCue represents
  end: number; // The last second on the timeline that this SpriteCue represents
  dimensions: {
    x: number; // The X coordinate in the spritesheet of the sprite, in px
    y: number; // The Y coordinate in the spritesheet of the sprite, in px
    width: number; // The width of the sprite, in px
    height: number; // The height of the sprite, in px
  };
}

The size of the sprites varies depending on content. By default getTimelineSpriteCues will look for Sprites that are as close as possible to a quarter of the width of the player, the most common size available is 160px wide.

Note

Only VOD assets have SpriteCues.

Events

There are multiple methods available to work with events from the player

  • player.on/player.addEventListener - listen to an event
  • player.once - listen to an event once
  • player.off/player.removeEventListener - remove an event listener
  • player.onAll - listen to all events
  • player.offAll - remove an event listener added with player.onAll

Example:

const handler = () => {
  console.log(`[Red Bee Player] Playing`);
};

// handler will be called once when the player dispatches the PLAYING event
player.once(PlayerEvents.PLAYING, handler);

// handler will be called whenever the player dispatches the PLAYING event
player.on(PlayerEvents.PLAYING, handler;

// handler will never be called again
player.removeEventListener(PlayerEvents.PLAYING, handler);

const allHandler = (event, data) => {
  console.log(`[RedBeePlayer] ${event}`, data);
} 
// every event dispatched by the player will be handled by the allHandler
player.onAll(({ event, data }) => {
  ...
});

// the allHandler will not be called the next time an event is dispatched. 
player.offAll(allHandler);

If you use TypeScript the event listeners are fully typed.

player.on(PlayerEvents.STATE_CHANGED, (data) => {
  // data will have the type PlayerState
});

available events when not casting

const PlayerEvents = {
  PLAY: "player:play",
  PAUSE: "player:pause",
  STOP: "player:stopped",
  START: "player:start",
  RESUME: "player:resume",
  PLAYING: "player:playing",
  SEEKING: "player:seeking",
  SEEK_TIME_CHANGE: "player:seek_time_change",
  SEEKED: "player:seeked",
  TIME_UPDATE: "player:timeupdate",
  ENDED: "player:ended",
  VOLUME_CHANGE: "player:volumechange",
  ERROR: "player:error",
  CAST_ERROR: "player:cast_error",
  LOADING: "player:loading",
  LOADED: "player:loaded",
  LOAD_START: "player:load_start",
  BUFFERING: "player:buffering",
  BUFFERED: "player:buffered",
  ID3: "player:id3",
  BITRATE_CHANGED: "player:bitrate_changed",
  CDN_CHANGED: "player:cdn_changed",
  AUDIO_CHANGED: "player:audio_changed",
  SUBTITLE_CHANGED: "player:subtitle_changed",
  LICENSE_EXPIRED: "player:license_expired",
  DROPPED_FRAMES: "player:dropped_frames",
  DRM_UPDATE: "player:drm:update",
  STATE_CHANGED: "player:state_changed",
  PROGRAM_CHANGED: "player:program_changed",
  NOT_ENTITLED: "player:not_entitled",
  BLACKOUT: "player:blackout",
  EMPTY_SLOT: "player:empty_slot",
  CAST_START: "player:cast:start",
  CAST_STOP: "player:cast:stop",
  AIRPLAY_START: "player:airplay:start",
  AIRPLAY_STOP: "player:airplay:stop",
  AD_START: "player:ad:start",
  AD_COMPLETE: "player:ad:complete",
  ADBLOCK_START: "player:adblock:start",
  ADBLOCK_COMPLETE: "player:adblock:complete",
  INTRO_START: "player:intro:start",
  INTRO_END: "player:intro:end",
  CHAPTER_START: "player:chapter:start",
  CHAPTER_END: "player:chapter:end",
  MARKER: "player:marker",
  METADATA_EVENT: "player:metadata_event",
  SESSION_ACQUIRED: "player:session_acquired",
  PLAYER_SETUP_COMPLETED: "player:setup_completed",
  ENTITLEMENT_GRANTED: "player:entitlement_granted",
} as const;

While casting, only the STATE_CHANGED, PROGRAM_CHANGED, CAST_START and CAST_STOP events are used.

Timed metadata events

The player will emit a METADATA_EVENT when a EXT-X-DATERANGE tag is encountered in the HLS manifest. Similarly, the player will emit a METADATA_EVENT when a period with an EventStream schemeIdUri appears in the schema that matches the metadataURIs that can be set in the Player options. Important to note is that if the metadataURIs is set to an empty list, the player will emit all events that appear in the MPEG-DASH stream if Shaka Player is used . if the metadataURIs option is not set the player will not emit any METADATA_EVENT events.

The event will have the following properties:

interface IMetadataEvent {
  event: any; // The event
  engineName: string; // The name of the player engine that generated the event
  engineVersion?: string; // The version of the player engine that generated the event
}

Depending on the engine type the event will have different properties. The default behavior of the player is to prioritize the use of the MPEG-DASH stream when available over the HLS stream for non Safari browsers.

For HLS on non Safari browsers the event will be a list with the following properties:

engineName: "Hls.js"
engineVersion: "1.1.5"
event: [
  "EXT-X-DATERANGE",
  "ID=\"123456\",START-DATE=\"2022-08-30T12:31:55.040Z\",X-COM-DAICONNECT-TRACK=\"abc1234",
  ...
]

For HLS on Safari browsers the event object will have the following properties:

engineName: "Native HTML Video"
event: [
  DataCue {
    data: null,
    value: {key: "X-COM-DAICONNECT-TRACK", data: "abc1234"},
    type: "com.apple.quicktime.HLS",
  }
  ...
]

For MPEG-DASH streams when using Shaka Player as engine the event object will have the following properties: See: https://shaka-player-demo.appspot.com/docs/api/shaka.extern.html#.TimelineRegionInfo for more information.

engineName: "Shaka Player"
engineVersion: "v4.1.2"
event: {
  endTime: 1661864509.842636
  eventElement: Event, // The event with the tracking elements
  schemeIdUri: "urn:daiconnect:dai:2019:xml",
  startTime: 1661864509.842636,
  timeStamp: 870455.3000000119,
  type: "timelineregionenter",
  seekable: {start: 1661863914.943625, end: 1661864514.943625},
  utcCurrentTime: 1661864514572.273,
  utcDuration: 1661864519445.625,
  utcSeekable: {start: 1661863919445.625, end: 1661864519445.625},
  ...
}

For MPEG-DASH streams when using dash.js as engine the event object will have the following properties:

engineName: "Dashjs"
engineVersion: "4.4.1"
event: {
  type: "urn:scte:scte35:2014:xml+bin",
  event: {
    calculatedPresentationTime: 1680084927.36,
    duration: 38.4,
    eventStream: {
      adaptionSet: null
      period: {
        duration: Infinity,
        id: "1",
        index: 0,
        mpd: Object {
          suggestedPresentationDelay: 0,
          timeShiftBufferDepth: 600,
          maxSegmentDuration: 3,
          ...
        },
        nextPeriodId: null,
        start: 0,
      }​,
      presentationTimeOffset: 0,​​
      representation: null,​​
      schemeIdUri: "urn:scte:scte35:2014:xml+bin",​​
      timescale: 1000,
      value: "",
    },
    id: 13889591,
    messageData: [ 252, 48, 32, ... ], // Uint8Array of the SCTE35 message data (binary)
    presentationTime: 1680084927360,
    presentationTimeDelta: NaN,
    triggeredReceivedEvent: true,
    triggeredStartEvent: true,
    ...
  }
}

Player Cue Points

The asset may contain an array of MarkerPoints. Depending on the type of Marker, it gets treated differently:

A marker of type INTRO will trigger PlayerEvents of either INTRO_START or INTRO_END. The trigger PlayerEvents.INTRO_START will, as part of the player, present a button inside the video element containing a skip icon and whatever title is given to the intro marker. This button give the user an option to skip the intro marker duration and seek to the endOffset of the intro marker, if clicked.

Similarly, a marker of type CHAPTER will trigger PlayerEvents of either CHAPTER_START or CHAPTER_END. However, these events are not presented to the endusers as a button but are merely there as a convenience for third party skins to take action on. If present, marker of type CHAPTER does however get listed in the Content Marker Menu, next to Settings, where if clicked will seek the user to the starttime, i.e. offset of said Chapter. In this list, whatever title is given to the content marker is presented next to the time of the content marker offset.

A marker of type POINT, does not have an endOffset. These are simply a point of interest in time. i.e a goal in a fotball game. These markers are, similarly to markers of type CHAPTER, presented in the Content Marker Menu of the video element and, if clicked, will seek the user to that point in time. Whatever title is given to the content marker is presented next to the time of the content marker offset. Marker of type POINT triggers a PlayerEvent of type MARKER so that third party skins can take action on it.

Lastly, a marker of type CREDITS does not, like POINT, hold an endOffset. They are also simply a point of interest in time, but can be used to trigger events like "Push Next Content" or "Watch Next" suggestions. They are also available on PlayerEvents.Marker but are not presented in the list of Content Markers in the Content Marker Menu.

On all PlayerEvents, the actual content marker is available so that developers can do additional checks of type, offset etc.

export const MarkerType = {
  INTRO: "INTRO",
  CREDITS: "CREDITS",
  POINT: "POINT",
  CHAPTER: "CHAPTER"
} as const;

class MarkerPoint extends WithLocalized {
  offset: number; //start point in millisecond
  endOffset?: number; //end point in milliseconds, omitted in MarkerType "POINT" and "CREDITS"
  type: MarkerType;
}

If you do not want to listen to the different PlayerEvents, or need the markers up front to show an index or mark on the timeline, all available content markers are exposed on playerState.contentMarkers. If there are no content markers on the specific asset, playerState.contentMarkers will return an empty array.

As you may have multiple intros, for example one being recap and the other being the actual intro, a state of the active intro marker is exposed on metadata.activeIntro. This will default to null if there is no active Intro at that point in time.

the skip intro button is visible for 2.5 times the time set for settings.hideControlsTimer. If omitted, the button gets hidden after 7 seconds.

Chromecast

Chromecast support is enabled by default using the default unbranded RBM receiver.

Note

The player will include the Google Cast API library if needed, do not manually include that script on your site.

Custom skin

To implement chromecast support in your custom skin please use the google-cast-launcher webcomponent, more information is available here.

If you want to build a custom cast button please contact your RBM representative.

Custom receiver

To build a custom receiver follow the instruction here

Subtitles

Do you want to customize the subtitle style? You can do this by overriding the CSS for the subtitle cues with .redbee-player-subtitle-cue as of as of v0.65.0. We recommend not using an older player version than 0.65.0 for subtitle styling, but if you do, you can style cues with .redbee-player-subtitle-container span.

Example CSS

.redbee-player-subtitle-cue {
  background: rgba(0, 0, 0, 0.5);
  border-radius: 0.5em;
  padding: 0.5em;
}

The subtitle cue container element by default covers the whole screen. If you want to change that, then you can override the css for .redbee-player-subtitle-container. Note that as of v0.65.0 the default RedBeePlayer skin will regularly try to set the margin-bottom property of this container to avoid rendering over the subtitles.

Note

The WebVTT spec is a living standard, and therefore will have partial support in browsers and player engines. We try to work around this and support as much of the spec as we can, but it's not possible for us to support all subfeatures of styling and positioning for all engines and browsers.

Error handling

Errors can be caught on the error event as mentioned above

const player = new RedBeePlayer(options);
player.on(PlayerEvents.ERROR, (error) => {
  console.error(error);
})

The data object in such scenario is structured in the following way:

class PlayerError {
  message: string;
  category: string;
  metadata: {
    type: string;
    code?: number;
    rawError?: any;
  }
};

The toString() method of the error returns a formatted string of all the information except rawError.

Cast error

If there is an issue with casting the player will emit a PlayerEvents.CAST_ERROR with the same error object as above. Note that CAST_ERROR is only emitted if the cast session fails to start, not if playback fails on the cast device itself. Our recommendation is to inform the user that casting fails but let them stop the cast session themselves, otherwise they may not realize that there is something wrong with the cast device or network.