@skylineos/clsp-player
Version:
Skyline Technology Solutions' CLSP Video Player. Stream video in near-real-time in modern browsers.
282 lines (237 loc) • 7.7 kB
JavaScript
;
/**
* This file needs to use `require` rather than `import` to be able to be used
* by webpack.
*/
const packageJson = require('../../../package.json');
const Logger = require('./Logger');
let _isPlayerLoggingEnabled = true;
// CLSP default port for SFS >= 5.2.0 is 80
// CLSP default port for SFS < 5.2.0 is 9001
const DEFAULT_CLSP_PORT = 80;
const DEFAULT_CLSPS_PORT = 443;
// Locally-scoped value that maintains the clsp and clsps port states.
//
// @see - getDefaultStreamPort
// @see - setDefaultStreamPort
//
// @todo - state / config could be managed better than this
const streamPorts = {
clsp: DEFAULT_CLSP_PORT,
clsps: DEFAULT_CLSPS_PORT,
};
/**
* The name of the CLSP Player library as defined in `package.json` without the
* group name.
*
* @type {String}
*/
const name = packageJson.name.split('/').pop();
/**
* The version of the CLSP Player library. Follows semver.
*
* @type {String}
*/
const version = packageJson.version;
// @todo - remove this side-effect
const logger = Logger(version).factory();
/**
* The oldest Chrome browser version supported by CLSP Player.
*
* @type {Number}
*/
const MINIMUM_CHROME_VERSION = 53;
/**
* The MIME type required for CLSP Player to be able to play the stream.
*
* @todo - this mime type, though used in the videojs plugin, and
* seemingly enforced, is not actually enforced. The only enforcement
* done is requiring the user provide this string on the video element
* in the DOM. The codecs that are supplied by the SFS's vary. Here
* are some "valid", though not enforced mimeCodec values I have come
* across:
* - video/mp4; codecs="avc1.4DE016"
* - video/mp4; codecs="avc1.42E00C"
* - video/mp4; codecs="avc1.42E00D"
*
* @type {String}
*/
const SUPPORTED_MIME_TYPE = "video/mp4; codecs='avc1.42E01E'";
/**
* The amount of time (in seconds) before a stream times out.
*
* Note that this timeout value should be treated as the minimum value to
* support Vero tours and high-quality streams.
*
* @type {Number}
*/
const DEFAULT_STREAM_TIMEOUT = 20;
/**
* Determine whether or not the CLSP Player is supported in the current browser.
*
* @todo - we are currently manually checking useragentstring - we should find a
* library that can check browser type for us
*
* @returns {Boolean}
* `true` if the browser is supported by CLSP Player
* `false` if the browser is not supported by CLSP Player
*/
function isBrowserCompatable () {
// @todo - at one time, this was needed for browsers on MacOS - is this still
// necessary?
window.MediaSource = window.MediaSource || window.WebKitMediaSource;
if (!window.MediaSource) {
console.error('Media Source Extensions not supported in your browser, unable to load CLSP Player');
return false;
}
const isInternetExplorer = navigator.userAgent.toLowerCase().indexOf('trident') > -1;
if (isInternetExplorer) {
logger.debug('Detected Internet Explorer browser, which is not supported.');
return false;
}
const isEdge = navigator.userAgent.toLowerCase().indexOf('edge') > -1;
if (isEdge) {
logger.debug('Detected older Edge browser, which is not supported');
return false;
}
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
if (isFirefox) {
logger.debug('Detected Firefox browser');
return true;
}
// Most browsers have "Chrome" in their user agent. The above filters rule
// out Internet Explorer and Edge, so we are going to assume that if we're at
// this point, we're really dealing with Chrome.
const isChrome = Boolean(window.chrome);
if (!isChrome) {
return false;
}
try {
// Rather than accounting for match returning null, we'll catch the error
const chromeVersion = parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10);
logger.debug(`Detected Chrome version ${chromeVersion}`);
return chromeVersion >= MINIMUM_CHROME_VERSION;
}
catch (error) {
logger.critical('Unable to detect Chrome version');
logger.critical(error);
return false;
}
}
/**
* Check to see if the passed mimeType is supported by CLSP Player.
*
* @param {String} mimeType
* Will check to see if this mimeType is supported
*
* @returns {Boolean}
* `true` if the mimeType is supported by CLSP Player
* `false` if the mimeType is not supported by CLSP Player
*/
function isSupportedMimeType (mimeType) {
return mimeType === SUPPORTED_MIME_TYPE;
}
/**
* @typedef {Object} PageVisibilityApiPropertyNames
* @property {String} hiddenStateName
* The property name used for the `document.hidden` property
* @property {String} visibilityChangeEventName
* The property name used for the `document.visibilityChange` event name
*/
/**
* Get the property names used by this browser for the Page Visibility API.
*
* @returns {PageVisibilityApiPropertyNames}
*/
function getWindowStateNames () {
logger.debug('Determining Page_Visibility_API property names.');
// @todo - this check is needed to support these utils being imported by
// webpack. there is probably a more elegant way to handle this scenario.
if (typeof document === 'undefined') {
return {
hiddenStateName: '',
visibilityChangeEventName: '',
};
}
// @see - https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
if (typeof document.hidden !== 'undefined') {
logger.debug('Using standard Page_Visibility_API property names.');
return {
hiddenStateName: 'hidden',
visibilityChangeEventName: 'visibilitychange',
};
}
// @todo - do we need this since we don't support IE or old Edge?
if (typeof document.msHidden !== 'undefined') {
logger.debug('Using Microsoft Page_Visibility_API property names.');
return {
hiddenStateName: 'msHidden',
visibilityChangeEventName: 'msvisibilitychange',
};
}
if (typeof document.webkitHidden !== 'undefined') {
logger.debug('Using Webkit Page_Visibility_API property names.');
return {
hiddenStateName: 'webkitHidden',
visibilityChangeEventName: 'webkitvisibilitychange',
};
}
logger.critical('Unable to use the page visibility api - switching tabs and minimizing the page may result in slow downs and page crashes.');
return {
hiddenStateName: '',
visibilityChangeEventName: '',
};
}
/**
* Get the default port number for the given protocol.
*
* @param {String} protocol
* The protocol to get the default port for. Must be a known protocol (e.g.
* `clsp` or `clsps`)
*/
function getDefaultStreamPort (protocol) {
return streamPorts[protocol];
}
/**
* Set the default port number for the given protocol.
*
* @param {String} protocol
* The protocol to set the default port for. Must be a known protocol (e.g.
* `clsp` or `clsps`)
*/
function setDefaultStreamPort (protocol, port) {
streamPorts[protocol] = port;
}
function enablePlayerLogging () {
_isPlayerLoggingEnabled = true;
}
function disablePlayerLogging () {
_isPlayerLoggingEnabled = false;
}
function isPlayerLoggingDisabled () {
return !_isPlayerLoggingEnabled;
}
const windowStateNames = getWindowStateNames();
function isDocumentHidden () {
return document[windowStateNames.hiddenStateName];
}
function isOnline () {
return window.navigator.onLine;
}
module.exports = {
name,
version,
MINIMUM_CHROME_VERSION,
SUPPORTED_MIME_TYPE,
DEFAULT_STREAM_TIMEOUT,
supported: isBrowserCompatable,
isSupportedMimeType,
windowStateNames,
isDocumentHidden,
isOnline,
getDefaultStreamPort,
setDefaultStreamPort,
enablePlayerLogging,
disablePlayerLogging,
isPlayerLoggingDisabled,
};