UNPKG

shaka-player

Version:
189 lines (165 loc) 4.87 kB
/*! @license * Shaka Player * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ goog.provide('shaka.device.Chromecast'); goog.require('shaka.device.AbstractDevice'); goog.require('shaka.device.DeviceFactory'); goog.require('shaka.device.IDevice'); goog.require('shaka.log'); goog.require('shaka.util.Lazy'); /** * @final */ shaka.device.Chromecast = class extends shaka.device.AbstractDevice { constructor() { if (!shaka.device.Chromecast.isChromecast_()) { throw new Error('Not a Chromecast device!'); } super(); /** @private {!shaka.util.Lazy<?number>} */ this.version_ = new shaka.util.Lazy(() => { // Looking for something like "Chrome/106.0.0.0" const match = navigator.userAgent.match(/Chrome\/(\d+)/); if (match) { return parseInt(match[1], /* base= */ 10); } return null; }); /** @private {!shaka.util.Lazy<shaka.device.Chromecast.OsType_>} */ this.osType_ = new shaka.util.Lazy(() => { let fieldToCheck = (navigator.userAgentData && navigator.userAgentData.platform) || navigator.userAgent; fieldToCheck = fieldToCheck.toLowerCase(); if (fieldToCheck.includes('android')) { return shaka.device.Chromecast.OsType_.ANDROID; } else if (fieldToCheck.includes('fuchsia')) { return shaka.device.Chromecast.OsType_.FUCHSIA; } else { return shaka.device.Chromecast.OsType_.LINUX; } }); } /** * @override */ getVersion() { return this.version_.value(); } /** * @override */ getDeviceName() { return 'Chromecast with ' + this.osType_.value(); } /** * @override */ getDeviceType() { return shaka.device.IDevice.DeviceType.CAST; } /** * @override */ getBrowserEngine() { return shaka.device.IDevice.BrowserEngine.CHROMIUM; } /** * @override */ supportsMediaCapabilities() { return super.supportsMediaCapabilities() && this.osType_.value() !== shaka.device.Chromecast.OsType_.LINUX; } /** * @override */ supportsSmoothCodecSwitching() { return this.osType_.value() !== shaka.device.Chromecast.OsType_.LINUX; } /** * @override */ seekDelay() { switch (this.osType_.value()) { case shaka.device.Chromecast.OsType_.ANDROID: return 0; case shaka.device.Chromecast.OsType_.FUCHSIA: return 3; default: return 1; } } /** * @override */ async detectMaxHardwareResolution() { // In our tests, the original Chromecast seems to have trouble decoding // above 1080p. It would be a waste to select a higher res anyway, given // that the device only outputs 1080p to begin with. // Chromecast has an extension to query the device/display's resolution. const hasCanDisplayType = window.cast && cast.__platform__ && cast.__platform__.canDisplayType; // Some hub devices can only do 720p. Default to that. const maxResolution = {width: 1280, height: 720}; try { if (hasCanDisplayType && await cast.__platform__.canDisplayType( 'video/mp4; codecs="avc1.640028"; width=3840; height=2160')) { // The device and display can both do 4k. Assume a 4k limit. maxResolution.width = 3840; maxResolution.height = 2160; } else if (hasCanDisplayType && await cast.__platform__.canDisplayType( 'video/mp4; codecs="avc1.640028"; width=1920; height=1080')) { // Most Chromecasts can do 1080p. maxResolution.width = 1920; maxResolution.height = 1080; } } catch (error) { // This shouldn't generally happen. Log the error. shaka.log.alwaysError('Failed to check canDisplayType:', error); // Now ignore the error and let the 720p default stand. } return maxResolution; } /** * @override */ adjustConfig(config) { super.adjustConfig(config); // Chromecast has long hardware pipeline that respond slowly to seeking. // Therefore we should not seek when we detect a stall on this platform. // Instead, default stallSkip to 0 to force the stall detector to pause // and play instead. config.streaming.stallSkip = 0; return config; } /** * @override */ supportsOfflineStorage() { return false; } /** * Check if the current platform is Vizio TV. * @return {boolean} * @private */ static isChromecast_() { return navigator.userAgent.includes('CrKey') && !navigator.userAgent.includes('VIZIO SmartCast'); } }; /** * @private * @enum {string} */ shaka.device.Chromecast.OsType_ = { ANDROID: 'Android', FUCHSIA: 'Fuchsia', LINUX: 'Linux', }; if (shaka.device.Chromecast.isChromecast_()) { shaka.device.DeviceFactory.registerDeviceFactory( () => new shaka.device.Chromecast()); }