Files
shaka-player/lib/util/platform.js
T
Joey Parrish 68902b9a86 fix(drm): Remove legacy Edge workarounds on new Edge
We only just gained the ability to test on new Chromium-based Edge
(google/generic-webdriver-server@475ec746), so we did not previously
know which workarounds were specific to legacy Edge.  Now all but one
of those workarounds has been limited to legacy Edge only, and will
not be applied to new Chromium-based Edge.

Change-Id: I70b7480ccb61064b796c3d9b41bbe95cabfdf850
2021-01-05 18:36:52 +00:00

293 lines
7.7 KiB
JavaScript

/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('shaka.util.Platform');
goog.require('shaka.util.Timer');
/**
* A wrapper for platform-specific functions.
*
* @final
*/
shaka.util.Platform = class {
/**
* Check if the current platform supports media source. We assume that if
* the current platform supports media source, then we can use media source
* as per its design.
*
* @return {boolean}
*/
static supportsMediaSource() {
// Browsers that lack a media source implementation will have no reference
// to |window.MediaSource|. Platforms that we see having problematic media
// source implementations will have this reference removed via a polyfill.
if (!window.MediaSource) {
return false;
}
// Some very old MediaSource implementations didn't have isTypeSupported.
if (!MediaSource.isTypeSupported) {
return false;
}
return true;
}
/**
* Returns true if the media type is supported natively by the platform.
*
* @param {string} mimeType
* @return {boolean}
*/
static supportsMediaType(mimeType) {
const video = shaka.util.Platform.anyMediaElement();
return video.canPlayType(mimeType) != '';
}
/**
* Check if the current platform is MS Edge.
*
* @return {boolean}
*/
static isEdge() {
// Legacy Edge contains "Edge/version".
// Chromium-based Edge contains "Edg/version" (no "e").
if (navigator.userAgent.match(/Edge?\//)) {
return true;
}
return false;
}
/**
* Check if the current platform is Legacy Edge.
*
* @return {boolean}
*/
static isLegacyEdge() {
// Legacy Edge contains "Edge/version".
// Chromium-based Edge contains "Edg/version" (no "e").
if (navigator.userAgent.match(/Edge\//)) {
return true;
}
return false;
}
/**
* Check if the current platform is MS IE.
*
* @return {boolean}
*/
static isIE() {
return shaka.util.Platform.userAgentContains_('Trident/');
}
/**
* Check if the current platform is a Tizen TV.
*
* @return {boolean}
*/
static isTizen() {
return shaka.util.Platform.userAgentContains_('Tizen');
}
/**
* Check if the current platform is a Tizen 4 TV.
*
* @return {boolean}
*/
static isTizen4() {
return shaka.util.Platform.userAgentContains_('Tizen 4');
}
/**
* Check if the current platform is a Tizen 3 TV.
*
* @return {boolean}
*/
static isTizen3() {
return shaka.util.Platform.userAgentContains_('Tizen 3');
}
/**
* Check if the current platform is a Tizen 2 TV.
*
* @return {boolean}
*/
static isTizen2() {
return shaka.util.Platform.userAgentContains_('Tizen 2');
}
/**
* Check if the current platform is a WebOS.
*
* @return {boolean}
*/
static isWebOS() {
return shaka.util.Platform.userAgentContains_('Web0S');
}
/**
* Check if the current platform is a Google Chromecast.
*
* @return {boolean}
*/
static isChromecast() {
return shaka.util.Platform.userAgentContains_('CrKey');
}
/**
* Check if the current platform is Google Chrome.
*
* @return {boolean}
*/
static isChrome() {
// The Edge user agent will also contain the "Chrome" keyword, so we need
// to make sure this is not Edge.
return shaka.util.Platform.userAgentContains_('Chrome') &&
!shaka.util.Platform.isEdge();
}
/**
* Check if the current platform is from Apple.
*
* Returns true on all iOS browsers and on desktop Safari.
*
* Returns false for non-Safari browsers on macOS, which are independent of
* Apple.
*
* @return {boolean}
*/
static isApple() {
return !!navigator.vendor && navigator.vendor.includes('Apple')
&& !shaka.util.Platform.isTizen();
}
/**
* Returns a major version number for Safari, or Safari-based iOS browsers.
*
* For example:
* - Safari 13.0.4 on macOS returns 13.
* - Safari on iOS 13.3.1 returns 13.
* - Chrome on iOS 13.3.1 returns 13 (since this is based on Safari/WebKit).
* - Chrome on macOS returns null (since this is independent of Apple).
*
* Returns null on Firefox on iOS, where this version information is not
* available.
*
* @return {?number} A major version number or null if not iOS.
*/
static safariVersion() {
// All iOS browsers and desktop Safari will return true for isApple().
if (!shaka.util.Platform.isApple()) {
return null;
}
// This works for iOS Safari and desktop Safari, which contain something
// like "Version/13.0" indicating the major Safari or iOS version.
let match = navigator.userAgent.match(/Version\/(\d+)/);
if (match) {
return parseInt(match[1], /* base= */ 10);
}
// This works for all other browsers on iOS, which contain something like
// "OS 13_3" indicating the major & minor iOS version.
match = navigator.userAgent.match(/OS (\d+)(?:_\d+)?/);
if (match) {
return parseInt(match[1], /* base= */ 10);
}
return null;
}
/**
* Guesses if the platform is a mobile one (iOS or Android).
*
* @return {boolean}
*/
static isMobile() {
if (/(?:iPhone|iPad|iPod|Android)/.test(navigator.userAgent)) {
// This is Android, iOS, or iPad < 13.
return true;
}
// Starting with iOS 13 on iPad, the user agent string no longer has the
// word "iPad" in it. It looks very similar to desktop Safari. This seems
// to be intentional on Apple's part.
// See: https://forums.developer.apple.com/thread/119186
//
// So if it's an Apple device with multi-touch support, assume it's a mobile
// device. If some future iOS version starts masking their user agent on
// both iPhone & iPad, this clause should still work. If a future
// multi-touch desktop Mac is released, this will need some adjustment.
//
// As of January 2020, this is mainly used to adjust the default UI config
// for mobile devices, so it's low risk if something changes to break this
// detection.
return shaka.util.Platform.isApple() && navigator.maxTouchPoints > 1;
}
/**
* Check if the user agent contains a key. This is the best way we know of
* right now to detect platforms. If there is a better way, please send a
* PR.
*
* @param {string} key
* @return {boolean}
* @private
*/
static userAgentContains_(key) {
const userAgent = navigator.userAgent || '';
return userAgent.includes(key);
}
/**
* For canPlayType queries, we just need any instance.
*
* First, use a cached element from a previous query.
* Second, search the page for one.
* Third, create a temporary one.
*
* Cached elements expire in one second so that they can be GC'd or removed.
*
* @return {!HTMLMediaElement}
*/
static anyMediaElement() {
const Platform = shaka.util.Platform;
if (Platform.cachedMediaElement_) {
return Platform.cachedMediaElement_;
}
if (!Platform.cacheExpirationTimer_) {
Platform.cacheExpirationTimer_ = new shaka.util.Timer(() => {
Platform.cachedMediaElement_ = null;
});
}
Platform.cachedMediaElement_ = /** @type {HTMLMediaElement} */(
document.getElementsByTagName('video')[0] ||
document.getElementsByTagName('audio')[0]);
if (!Platform.cachedMediaElement_) {
Platform.cachedMediaElement_ = /** @type {!HTMLMediaElement} */(
document.createElement('video'));
}
Platform.cacheExpirationTimer_.tickAfter(/* seconds= */ 1);
return Platform.cachedMediaElement_;
}
};
/** @private {shaka.util.Timer} */
shaka.util.Platform.cacheExpirationTimer_ = null;
/** @private {HTMLMediaElement} */
shaka.util.Platform.cachedMediaElement_ = null;