Google Cast (Chromecast) Support

Overview

Fastevo MP2 Player can stream protected content to Google Cast devices (Chromecast, Android TV, Cast-enabled TVs). The integration uses two pieces:

  1. Sender — the regular Fastevo player running in your browser. It sends the manifest URL, DRM credentials, metadata, and (optionally) anti-piracy steganography configuration to the Cast device.
  2. Receiver — a standalone Cast app provided by Fastevo. It runs on the TV / Chromecast device itself, plays the protected media using its own Shaka Player instance, signs DRM license requests with the same trust chain as the sender, and renders the optional steganography overlay.

The receiver app is a separate HTML bundle deployed alongside the sender at /<release-path>/logic/cast/receiver.html.


Compatibility

  • DRM: Widevine only. Cast sessions are not started for content protected with FairPlay or PlayReady (the cast button stays inactive).
  • Sender browsers: any browser that supports Google Cast — primarily Chrome (desktop) and Chrome on Android. iOS Safari does not support starting Google Cast sessions; viewers on Apple devices should use AirPlay instead.
  • Live streams: same model as the sender — supported when the manifest is reachable from the Cast device's network and the license server accepts requests from that origin.

Setup

Step 1 — Register a Cast receiver app with Google

  1. Sign in to the Google Cast SDK Developer Console (opens in a new tab).
  2. Add a new Custom Receiver app and point its receiver URL to:
    https://<your-player-host>/<release-path>/logic/cast/receiver.html
    For Fastevo's default deployment that is something like:
    https://player.fastevo.net/release/logic/cast/receiver.html
  3. Publish the receiver. Google will assign you a Cast Application ID (an 8-character alphanumeric string).
⚠️

The receiver URL must be served over HTTPS and be publicly reachable from the Cast device's network. Cast SDK refuses HTTP and rejects unreachable URLs.

Step 2 — Configure the player with your Cast Application ID

The player reads the Cast Application ID at build time from the GOOGLE_CAST_APP_ID environment variable. Set it in your .env (production) or .env.devels (devel) before running npm run build:

GOOGLE_CAST_APP_ID=AB12CD34

When the variable is unset (or empty), Cast support is silently disabled — no receiver is attempted, no cast button appears, no events fire. This makes it safe to run dev builds without a Cast registration.

Step 3 — Allow the receiver origin on your license server

The receiver runs on the Cast device's IP and origin, not on your sender's origin. If your Widevine license server enforces an Origin allowlist or CORS rules, add the host of your receiver URL to the allowlist. Otherwise the receiver will fail to acquire a license.

Step 4 — Allow access to your manifest from the Cast network

The Cast device fetches the manifest URL directly. Make sure it's reachable from the same network the Cast device is on (typically the local Wi-Fi). Tokens / signed URLs already in use on the sender are propagated to the receiver, so the same access controls apply.


How a Cast session starts

Once configured, casting works the same way as any other Cast-enabled webpage:

  1. The viewer loads the player on a desktop Chrome browser on the same network as a Chromecast.
  2. Chrome's native Cast UI (the cast icon in the URL bar) detects available devices and lists them in its dropdown.
  3. The viewer picks a device → Chrome launches the receiver URL on that device → the receiver loads.
  4. The sender (your player) automatically transfers the playback session: it hands the manifest URL, license URL, Authorization header, time-skew compensation, server-side height constraint, subtitles, poster, and any client steganography configuration to the receiver via castProxy.setAppData(...).
  5. The receiver configures Shaka Player with the supplied DRM details, signs license requests with the same expirable signature scheme as the sender, optionally initializes steganography rendering, and starts playback.

The viewer's TV now plays the content; the sender browser shows a "casting" indicator and acts as a remote.


Listening to Cast events

When a Cast session starts, the player emits a castStarted event you can listen to via the standard mechanisms documented in Player Events:

container.addEventListener("castStarted", function (e) {
  console.log("Cast session started", e.detail);
  // e.detail = { castPlatform: "googleCast" }
  // (or { castPlatform: "airplay" } when AirPlay is the underlying transport)
});
 
// or via the player instance:
var player = window.players["my-video-container"];
player.on("castStarted", function (data) {
  console.log("Cast session started", data);
});

The event fires once when the session opens; it does not re-fire for periodic status updates during the session.


What gets propagated to the receiver

The sender packages the following into the Cast app data:

FieldNotes
manifest.urlFully signed URL (with playback access token query params).
manifest.contentTypeInferred from the URL — application/x-mpegurl for HLS, application/vnd.ms-sstr+xml for SmoothStream, otherwise application/dash+xml.
manifest.mediaTypeThe session's content type (video, audio, image).
drm.licenseUrlWidevine license server URL.
drm.headers.AuthorizationThe playback session exchanges token.
drm.timeDifferenceWithServerInMillisecondsClock skew compensation, used by the receiver to sign license requests with the correct expiration window.
metadata.posterUsed as the video poster on the receiver and as the Cast media image.
features.autoPlay / features.loopInherits the sender's options.
constraints.maxVideoHeightThe server-provided height cap (see Playback Tokensconstraints.maxVideoHeight). The receiver respects the same cap.
subtitles[]Per-language signed VTT URLs.
stegoClient steganography details and badge configuration when steganography is enabled for the session.
protectionDetails, playerConfigurationForwarded for the receiver's reference.

If the session is not Widevine-protected, no Cast app data is built and the receiver is never engaged for that session.


AirPlay vs Google Cast

Both transports are exposed by the player when their respective platforms are available:

  • Google Cast — initiated from Chrome's native Cast UI. Targets Chromecast / Cast-enabled devices.
  • AirPlay — initiated from Safari / iOS / iPadOS / macOS. Configured separately via enableNonSecureAirplayCasting in the player configuration.

Both fire the same castStarted event when a session opens; the castPlatform field on the event payload distinguishes them ("googleCast" vs "airplay").


Out of scope (current limitations)

  • PlayReady / FairPlay receivers: only Widevine-protected sessions are cast.
  • Color-map steganography on the TV: the receiver renders standard steganography (badges, anti-tampering layer) but does not currently fetch and apply the per-session color map. This is a follow-up.
  • Cast button inside the player UI: today the cast button appears in Chrome's URL bar via the native Cast extension. An in-player button is on the roadmap.
  • Mobile sender on iOS: iOS Safari does not allow starting Google Cast sessions from a webpage. Use AirPlay on Apple mobile devices.

Additional Resources