/*! @license
* Shaka Player
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('shaka.device.DefaultBrowser');
goog.require('shaka.debug.RunningInLab');
goog.require('shaka.device.AbstractDevice');
goog.require('shaka.device.DeviceFactory');
goog.require('shaka.device.IDevice');
goog.require('shaka.drm.DrmUtils');
goog.require('shaka.util.Lazy');
/**
* @final
*/
shaka.device.DefaultBrowser = class extends shaka.device.AbstractDevice {
constructor() {
super();
/** @private {!shaka.util.Lazy<?number>} */
this.version_ = new shaka.util.Lazy(() => {
// Looking for something like "Chrome/106.0.0.0" or Firefox/135.0
const match = navigator.userAgent.match(/(Chrome|Firefox)\/(\d+)/);
if (match) {
return parseInt(match[2], /* base= */ 10);
}
return null;
});
/** @private {!shaka.util.Lazy<string>} */
this.deviceName_ = new shaka.util.Lazy(() => {
// Legacy Edge contains "Edge/version".
// Chromium-based Edge contains "Edg/version" (no "e").
if (navigator.userAgent.match(/Edge?\//)) {
return 'Edge';
} else if (navigator.userAgent.includes('Chrome')) {
return 'Chrome';
} else if (navigator.userAgent.includes('Firefox')) {
return 'Firefox';
}
return 'Unknown';
});
/** @private {!shaka.util.Lazy<boolean>} */
this.isWindows_ = new shaka.util.Lazy(() => {
// Try the newer standard first.
if (navigator.userAgentData && navigator.userAgentData.platform) {
return navigator.userAgentData.platform.toLowerCase() == 'windows';
}
// Fall back to the old API, with less strict matching.
if (!navigator.platform) {
return false;
}
return navigator.platform.toLowerCase().includes('win32');
});
/** @private {!shaka.util.Lazy<boolean>} */
this.supportsSmoothCodecSwitching_ = new shaka.util.Lazy(() => {
if (!navigator.userAgent.match(/Edge?\//)) {
return true;
}
return !this.isWindows_.value();
});
/** @private {!shaka.util.Lazy<boolean>} */
this.isSonyTV_ = new shaka.util.Lazy(() => {
return navigator.userAgent.includes('sony.hbbtv.tv.G5');
});
}
/**
* @override
*/
getVersion() {
return this.version_.value();
}
/**
* @override
*/
getDeviceName() {
return this.deviceName_.value();
}
/**
* @override
*/
requiresEncryptionInfoInAllInitSegments(keySystem) {
if (shaka.drm.DrmUtils.isPlayReadyKeySystem(keySystem)) {
return this.deviceName_.value() === 'Edge' && this.isWindows_.value();
}
return false;
}
/**
* @override
*/
requiresClearAndEncryptedInitSegments() {
return this.deviceName_.value() === 'Edge' && this.isWindows_.value();
}
/**
* @override
*/
insertEncryptionDataBeforeClear() {
return this.deviceName_.value() === 'Edge' && this.isWindows_.value(); ;
}
/**
* @override
*/
supportsSmoothCodecSwitching() {
return this.supportsSmoothCodecSwitching_.value();
}
/**
* @override
*/
adjustConfig(config) {
super.adjustConfig(config);
if (this.isWindows_.value()) {
// Other browsers different than Edge only supports PlayReady with the
// recommendation keysystem on Windows, so we do a direct mapping here.
// Firefox supports PlayReady 2000 (SW) and 3000 (HW).
// Chromium support PlayReady 3000 (HW) only.
switch (this.deviceName_.value()) {
case 'Firefox':
config.drm.keySystemsMapping = {
'com.microsoft.playready':
'com.microsoft.playready.recommendation',
};
break;
case 'Chrome':
config.drm.keySystemsMapping = {
'com.microsoft.playready':
'com.microsoft.playready.recommendation.3000',
'com.microsoft.playready.recommendation':
'com.microsoft.playready.recommendation.3000',
};
break;
}
}
return config;
}
/**
* @override
*/
returnLittleEndianUsingPlayReady() {
return this.deviceName_.value() === 'Edge' || this.isSonyTV_.value();
}
/**
* @override
*/
createMediaKeysWhenCheckingSupport() {
if (goog.DEBUG && shaka.debug.RunningInLab && this.isWindows_.value() &&
this.getBrowserEngine() === shaka.device.IDevice.BrowserEngine.GECKO) {
return false;
}
return true;
}
/**
* @override
*/
disableHEVCSupport() {
// It seems that HEVC on Firefox Windows is incomplete.
return this.isWindows_.value() &&
this.getBrowserEngine() === shaka.device.IDevice.BrowserEngine.GECKO;
}
};
shaka.device.DeviceFactory.registerDefaultDeviceFactory(
() => new shaka.device.DefaultBrowser());