diff --git a/src/js/poster-image.js b/src/js/poster-image.js index a606acf72d..7d6cba2f77 100644 --- a/src/js/poster-image.js +++ b/src/js/poster-image.js @@ -8,15 +8,21 @@ import * as Dom from './utils/dom.js'; import * as browser from './utils/browser.js'; /** - * The component that handles showing the poster image. + * A `ClickableComponent` that handles showing the poster image for the player. * - * @param {Player|Object} player - * @param {Object=} options - * @extends Button - * @class PosterImage + * @extends ClickableComponent */ class PosterImage extends ClickableComponent { + /** + * Create an instance of this class. + * + * @param {Player} player + * The `Player` that this class should attach to. + * + * @param {Object} [options] + * The key/value store of player options. + */ constructor(player, options) { super(player, options); @@ -25,9 +31,7 @@ class PosterImage extends ClickableComponent { } /** - * Clean up the poster image - * - * @method dispose + * Clean up and dispose of the `PosterImage`. */ dispose() { this.player().off('posterchange', this.update); @@ -35,10 +39,10 @@ class PosterImage extends ClickableComponent { } /** - * Create the poster's image element + * Create the `PosterImage`s DOM element. * * @return {Element} - * @method createEl + * The element that gets created. */ createEl() { const el = Dom.createEl('div', { @@ -61,11 +65,14 @@ class PosterImage extends ClickableComponent { } /** - * Event handler for updates to the player's poster source + * An {@link EventTarget~EventListener} for {@link Player#posterchange} events. + * + * @listens Player#posterchange * - * @method update + * @param {EventTarget~Event} [event] + * The `Player#posterchange` event that triggered this function. */ - update() { + update(event) { const url = this.player().poster(); this.setSrc(url); @@ -80,10 +87,10 @@ class PosterImage extends ClickableComponent { } /** - * Set the poster source depending on the display method + * Set the source of the `PosterImage` depending on the display method. * - * @param {String} url The URL to the poster source - * @method setSrc + * @param {String} url + * The URL to the source for the `PosterImage`. */ setSrc(url) { if (this.fallbackImg_) { @@ -102,11 +109,17 @@ class PosterImage extends ClickableComponent { } /** - * Event handler for clicks on the poster image + * An {@link EventTarget~EventListener} for clicks on the `PosterImage`. See + * {@link ClickableComponent#handleClick} for instances where this will be triggered. + * + * @listens tap + * @listens click + * @listens keydown * - * @method handleClick + * @param {EventTarget~Event} event + + The `click`, `tap` or `keydown` event that caused this function to be called. */ - handleClick() { + handleClick(event) { // We don't want a click to trigger playback when controls are disabled // but CSS should be hiding the poster to prevent that from happening if (this.player_.paused()) { diff --git a/src/js/tech/flash-rtmp.js b/src/js/tech/flash-rtmp.js index 14cd25e79f..45772d9c45 100644 --- a/src/js/tech/flash-rtmp.js +++ b/src/js/tech/flash-rtmp.js @@ -1,5 +1,15 @@ /** * @file flash-rtmp.js + * @module flash-rtmp + */ + +/** + * Add RTMP properties to the {@link Flash} Tech. + * + * @param {Flash} Flash + * The flash tech class. + * + * @mixin FlashRtmpDecorator */ function FlashRtmpDecorator(Flash) { Flash.streamingFormats = { @@ -7,10 +17,40 @@ function FlashRtmpDecorator(Flash) { 'rtmp/flv': 'FLV' }; + /** + * Join connection and stream with an ampersand. + * + * @param {string} connection + * The connection string. + * + * @param {string} stream + * The stream string. + */ Flash.streamFromParts = function(connection, stream) { return connection + '&' + stream; }; + /** + * The flash parts object that contains connection and stream info. + * + * @typedef {Object} Flash~PartsObject + * + * @property {string} connection + * The connection string of a source, defaults to an empty string. + * + * @property {string} stream + * The stream string of the source, defaults to an empty string. + */ + + /** + * Convert a source url into a stream and connection parts. + * + * @param {string} src + * the source url + * + * @return {Flash~PartsObject} + * The parts object that contains a connection and a stream + */ Flash.streamToParts = function(src) { const parts = { connection: '', @@ -44,14 +84,41 @@ function FlashRtmpDecorator(Flash) { return parts; }; + /** + * Check if the source type is a streaming type. + * + * @param {string} srcType + * The mime type to check. + * + * @return {boolean} + * - True if the source type is a streaming type. + * - False if the source type is not a streaming type. + */ Flash.isStreamingType = function(srcType) { return srcType in Flash.streamingFormats; }; // RTMP has four variations, any string starting // with one of these protocols should be valid + + /** + * Regular expression used to check if the source is an rtmp source. + * + * @property + * @type {RegExp} + */ Flash.RTMP_RE = /^rtmp[set]?:\/\//i; + /** + * Check if the source itself is a streaming type. + * + * @param {string} src + * The url to the source. + * + * @return {boolean} + * - True if the source url indicates that the source is streaming. + * - False if the shource url indicates that the source url is not streaming. + */ Flash.isStreamingSrc = function(src) { return Flash.RTMP_RE.test(src); }; @@ -63,9 +130,13 @@ function FlashRtmpDecorator(Flash) { Flash.rtmpSourceHandler = {}; /** - * Check if Flash can play the given videotype - * @param {String} type The mimetype to check - * @return {String} 'probably', 'maybe', or '' (empty string) + * Check if Flash can play the given mime type. + * + * @param {string} type + * The mime type to check + * + * @return {string} + * 'maybe', or '' (empty string) */ Flash.rtmpSourceHandler.canPlayType = function(type) { if (Flash.isStreamingType(type)) { @@ -77,9 +148,15 @@ function FlashRtmpDecorator(Flash) { /** * Check if Flash can handle the source natively - * @param {Object} source The source object - * @param {Object} options The options passed to the tech - * @return {String} 'probably', 'maybe', or '' (empty string) + * + * @param {Object} source + * The source object + * + * @param {Object} [options] + * The options passed to the tech + * + * @return {string} + * 'maybe', or '' (empty string) */ Flash.rtmpSourceHandler.canHandleSource = function(source, options) { const can = Flash.rtmpSourceHandler.canPlayType(source.type); @@ -96,12 +173,16 @@ function FlashRtmpDecorator(Flash) { }; /** - * Pass the source to the flash object - * Adaptive source handlers will have more complicated workflows before passing - * video data to the video element - * @param {Object} source The source object - * @param {Flash} tech The instance of the Flash tech - * @param {Object} options The options to pass to the source + * Pass the source to the flash object. + * + * @param {Object} source + * The source object + * + * @param {Flash} tech + * The instance of the Flash tech + * + * @param {Object} [options] + * The options to pass to the source */ Flash.rtmpSourceHandler.handleSource = function(source, tech, options) { const srcParts = Flash.streamToParts(source.src); diff --git a/src/js/tech/flash.js b/src/js/tech/flash.js index dd7ccefa59..c3274e8bfb 100644 --- a/src/js/tech/flash.js +++ b/src/js/tech/flash.js @@ -17,15 +17,23 @@ import assign from 'object.assign'; const navigator = window.navigator; /** - * Flash Media Controller - Wrapper for fallback SWF API + * Flash Media Controller - Wrapper for Flash Media API * - * @param {Object=} options Object of option names and values - * @param {Function=} ready Ready callback function + * @mixes FlashRtmpDecorator + * @mixes Tech~SouceHandlerAdditions * @extends Tech - * @class Flash */ class Flash extends Tech { + /** + * Create an instance of this Tech. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} ready + * Callback function to call when the `Flash` Tech is ready. + */ constructor(options, ready) { super(options, ready); @@ -59,13 +67,14 @@ class Flash extends Tech { this.on('seeked', function() { this.lastSeekTarget_ = undefined; }); + } /** - * Create the component's DOM element + * Create the `Flash` Tech's DOM element. * * @return {Element} - * @method createEl + * The element that gets created. */ createEl() { const options = this.options_; @@ -122,9 +131,7 @@ class Flash extends Tech { } /** - * Play for flash tech - * - * @method play + * Called by {@link Player#play} to play using the `Flash` `Tech`. */ play() { if (this.ended()) { @@ -134,20 +141,24 @@ class Flash extends Tech { } /** - * Pause for flash tech - * - * @method pause + * Called by {@link Player#pause} to pause using the `Flash` `Tech`. */ pause() { this.el_.vjs_pause(); } /** - * Get/set video + * A getter/setter for the `Flash` Tech's source object. + * > Note: Please use {@link Flash#setSource} + * + * @param {Tech~SourceObject} [src] + * The source object you want to set on the `Flash` techs. * - * @param {Object=} src Source object - * @return {Object} - * @method src + * @return {Tech~SourceObject|undefined} + * - The current source object when a source is not passed in. + * - undefined when setting + * + * @deprecated Since version 5. */ src(src) { if (src === undefined) { @@ -159,11 +170,14 @@ class Flash extends Tech { } /** - * Set video + * A getter/setter for the `Flash` Tech's source object. + * + * @param {Tech~SourceObject} [src] + * The source object you want to set on the `Flash` techs. * - * @param {Object=} src Source object - * @deprecated - * @method setSrc + * @return {Tech~SourceObject|undefined} + * - The current source object when a source is not passed in. + * - undefined when setting */ setSrc(src) { // Make sure source URL is absolute. @@ -178,18 +192,21 @@ class Flash extends Tech { } /** - * Returns true if the tech is currently seeking. - * @return {boolean} true if seeking + * Indicates whether the media is currently seeking to a new position or not. + * + * @return {boolean} + * - True if seeking to a new position + * - False otherwise */ seeking() { return this.lastSeekTarget_ !== undefined; } /** - * Set current time + * Returns the current time in seconds that the media is at in playback. * - * @param {Number} time Current time of video - * @method setCurrentTime + * @param {number} time + * Current playtime of the media in seconds. */ setCurrentTime(time) { const seekable = this.seekable(); @@ -207,13 +224,12 @@ class Flash extends Tech { } /** - * Get current time + * Get the current playback time in seconds * - * @param {Number=} time Current time of video - * @return {Number} Current time - * @method currentTime + * @return {number} + * The current time of playback in seconds. */ - currentTime(time) { + currentTime() { // when seeking make the reported time keep up with the requested time // by reading the time we're seeking to if (this.seeking()) { @@ -223,9 +239,11 @@ class Flash extends Tech { } /** - * Get current source + * Get the current source * * @method currentSrc + * @return {Tech~SourceObject} + * The current source */ currentSrc() { if (this.currentSource_) { @@ -235,9 +253,10 @@ class Flash extends Tech { } /** - * Get media duration + * Get the total duration of the current media. * - * @returns {Number} Media duration + * @return {number} + 8 The total duration of the current media. */ duration() { if (this.readyState() === 0) { @@ -249,35 +268,29 @@ class Flash extends Tech { } /** - * Load media into player - * - * @method load + * Load media into Tech. */ load() { this.el_.vjs_load(); } /** - * Get poster - * - * @method poster + * Get the poster image that was set on the tech. */ poster() { this.el_.vjs_getProperty('poster'); } /** - * Poster images are not handled by the Flash tech so make this a no-op - * - * @method setPoster + * Poster images are not handled by the Flash tech so make this is a no-op. */ setPoster() {} /** - * Determine if can seek in media + * Determine the time ranges that can be seeked to in the media. * - * @return {TimeRangeObject} - * @method seekable + * @return {TimeRange} + * Returns the time ranges that can be seeked to. */ seekable() { const duration = this.duration(); @@ -289,10 +302,10 @@ class Flash extends Tech { } /** - * Get buffered time range + * Get and create a `TimeRange` object for buffering. * - * @return {TimeRangeObject} - * @method buffered + * @return {TimeRange} + * The time range object that was created. */ buffered() { const ranges = this.el_.vjs_getProperty('buffered'); @@ -305,11 +318,12 @@ class Flash extends Tech { /** * Get fullscreen support - + * * Flash does not allow fullscreen through javascript - * so always returns false + * so this always returns false. * - * @return {Boolean} false - * @method supportsFullScreen + * @return {boolean} + * The Flash tech does not support fullscreen, so it will always return false. */ supportsFullScreen() { // Flash does not allow fullscreen through javascript @@ -317,12 +331,11 @@ class Flash extends Tech { } /** - * Request to enter fullscreen * Flash does not allow fullscreen through javascript - * so always returns false + * so this always returns false. * - * @return {Boolean} false - * @method enterFullScreen + * @return {boolean} + * The Flash tech does not support fullscreen, so it will always return false. */ enterFullScreen() { return false; @@ -360,8 +373,392 @@ for (let i = 0; i < _readOnly.length; i++) { _createGetter(_readOnly[i]); } +/** ------------------------------ Getters ------------------------------ **/ +/** + * Get the value of `rtmpConnection` from the swf. + * + * @method Flash.prototype.rtmpConnection + * @return {string} + * The current value of `rtmpConnection` on the swf. + */ + +/** + * Get the value of `rtmpStream` from the swf. + * + * @method Flash.prototype.rtmpStream + * @return {string} + * The current value of `rtmpStream` on the swf. + */ + +/** + * Get the value of `preload` from the swf. `preload` indicates + * what should download before the media is interacted with. It can have the following + * values: + * - none: nothing should be downloaded + * - metadata: poster and the first few frames of the media may be downloaded to get + * media dimensions and other metadata + * - auto: allow the media and metadata for the media to be downloaded before + * interaction + * + * @method Flash.prototype.preload + * @return {string} + * The value of `preload` from the swf. Will be 'none', 'metadata', + * or 'auto'. + */ + +/** + * Get the value of `defaultPlaybackRate` from the swf. + * + * @method Flash.prototype.defaultPlaybackRate + * @return {number} + * The current value of `defaultPlaybackRate` on the swf. + */ + +/** + * Get the value of `playbackRate` from the swf. `playbackRate` indicates + * the rate at which the media is currently playing back. Examples: + * - if playbackRate is set to 2, media will play twice as fast. + * - if playbackRate is set to 0.5, media will play half as fast. + * + * @method Flash.prototype.playbackRate + * @return {number} + * The value of `playbackRate` from the swf. A number indicating + * the current playback speed of the media, where 1 is normal speed. + */ + +/** + * Get the value of `autoplay` from the swf. `autoplay` indicates + * that the media should start to play as soon as the page is ready. + * + * @method Flash.prototype.autoplay + * @return {boolean} + * - The value of `autoplay` from the swf. + * - True indicates that the media ashould start as soon as the page loads. + * - False indicates that the media should not start as soon as the page loads. + */ + +/** + * Get the value of `loop` from the swf. `loop` indicates + * that the media should return to the start of the media and continue playing once + * it reaches the end. + * + * @method Flash.prototype.loop + * @return {boolean} + * - The value of `loop` from the swf. + * - True indicates that playback should seek back to start once + * the end of a media is reached. + * - False indicates that playback should not loop back to the start when the + * end of the media is reached. + */ + +/** + * Get the value of `mediaGroup` from the swf. + * + * @method Flash.prototype.mediaGroup + * @return {string} + * The current value of `mediaGroup` on the swf. + */ + +/** + * Get the value of `controller` from the swf. + * + * @method Flash.prototype.controller + * @return {string} + * The current value of `controller` on the swf. + */ + +/** + * Get the value of `controls` from the swf. `controls` indicates + * whether the native flash controls should be shown or hidden. + * + * @method Html5.prototype.controls + * @return {boolean} + * - The value of `controls` from the swf. + * - True indicates that native controls should be showing. + * - False indicates that native controls should be hidden. + */ + +/** + * Get the value of the `volume` from the swf. `volume` indicates the current + * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and + * so on. + * + * @method Flash.prototype.volume + * @return {number} + * The volume percent as a decimal. Value will be between 0-1. + */ + +/** + * Get the value of the `muted` from the swf. `muted` indicates the current + * audio level should be silent. + * + * @method Flash.prototype.muted + * @return {boolean} + * - True if the audio should be set to silent + * - False otherwise + */ + +/** + * Get the value of `defaultMuted` from the swf. `defaultMuted` indicates + * whether the media should start muted or not. Only changes the default state of the + * media. `muted` and `defaultMuted` can have different values. `muted` indicates the + * current state. + * + * @method Flash.prototype.defaultMuted + * @return {boolean} + * - The value of `defaultMuted` from the swf. + * - True indicates that the media should start muted. + * - False indicates that the media should not start muted. + */ + +/** + * Get the value of `networkState` from the swf. `networkState` indicates + * the current network state. It returns an enumeration from the following list: + * - 0: NETWORK_EMPTY + * - 1: NEWORK_IDLE + * - 2: NETWORK_LOADING + * - 3: NETWORK_NO_SOURCE + * + * @method Flash.prototype.networkState + * @return {number} + * The value of `networkState` from the swf. This will be a number + * from the list in the description. + */ + +/** + * Get the value of `readyState` from the swf. `readyState` indicates + * the current state of the media element. It returns an enumeration from the + * following list: + * - 0: HAVE_NOTHING + * - 1: HAVE_METADATA + * - 2: HAVE_CURRENT_DATA + * - 3: HAVE_FUTURE_DATA + * - 4: HAVE_ENOUGH_DATA + * + * @method Flash.prototype.readyState + * @return {number} + * The value of `readyState` from the swf. This will be a number + * from the list in the description. + */ + +/** + * Get the value of `readyState` from the swf. `readyState` indicates + * the current state of the media element. It returns an enumeration from the + * following list: + * - 0: HAVE_NOTHING + * - 1: HAVE_METADATA + * - 2: HAVE_CURRENT_DATA + * - 3: HAVE_FUTURE_DATA + * - 4: HAVE_ENOUGH_DATA + * + * @method Flash.prototype.readyState + * @return {number} + * The value of `readyState` from the swf. This will be a number + * from the list in the description. + */ + +/** + * Get the value of `initialTime` from the swf. + * + * @method Flash.prototype.initialTime + * @return {number} + * The `initialTime` proprety on the swf. + */ + +/** + * Get the value of `startOffsetTime` from the swf. + * + * @method Flash.prototype.startOffsetTime + * @return {number} + * The `startOffsetTime` proprety on the swf. + */ + +/** + * Get the value of `paused` from the swf. `paused` indicates whether the swf + * is current paused or not. + * + * @method Flash.prototype.paused + * @return {boolean} + * The value of `paused` from the swf. + */ + +/** + * Get the value of `ended` from the swf. `ended` indicates whether + * the media has reached the end or not. + * + * @method Flash.prototype.ended + * @return {boolean} + * - True indicates that the media has ended. + * - False indicates that the media has not ended. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended} + */ + +/** + * Get the value of `videoWidth` from the swf. `videoWidth` indicates + * the current width of the media in css pixels. + * + * @method Flash.prototype.videoWidth + * @return {number} + * The value of `videoWidth` from the swf. This will be a number + * in css pixels. + */ + +/** + * Get the value of `videoHeight` from the swf. `videoHeigth` indicates + * the current height of the media in css pixels. + * + * @method Flassh.prototype.videoHeight + * @return {number} + * The value of `videoHeight` from the swf. This will be a number + * in css pixels. + */ +/** ------------------------------ Setters ------------------------------ **/ + +/** + * Set the value of `rtmpConnection` on the swf. + * + * @method Flash.prototype.setRtmpConnection + * @param {string} rtmpConnection + * New value to set the `rtmpConnection` property to. + */ + +/** + * Set the value of `rtmpStream` on the swf. + * + * @method Flash.prototype.setRtmpStream + * @param {string} rtmpStream + * New value to set the `rtmpStream` property to. + */ + +/** + * Set the value of `preload` on the swf. `preload` indicates + * what should download before the media is interacted with. It can have the following + * values: + * - none: nothing should be downloaded + * - metadata: poster and the first few frames of the media may be downloaded to get + * media dimensions and other metadata + * - auto: allow the media and metadata for the media to be downloaded before + * interaction + * + * @method Flash.prototype.setPreload + * @param {string} preload + * The value of `preload` to set on the swf. Should be 'none', 'metadata', + * or 'auto'. + */ + +/** + * Set the value of `defaultPlaybackRate` on the swf. + * + * @method Flash.prototype.setDefaultPlaybackRate + * @param {number} defaultPlaybackRate + * New value to set the `defaultPlaybackRate` property to. + */ + +/** + * Set the value of `playbackRate` on the swf. `playbackRate` indicates + * the rate at which the media is currently playing back. Examples: + * - if playbackRate is set to 2, media will play twice as fast. + * - if playbackRate is set to 0.5, media will play half as fast. + * + * @method Flash.prototype.setPlaybackRate + * @param {number} playbackRate + * New value of `playbackRate` on the swf. A number indicating + * the current playback speed of the media, where 1 is normal speed. + */ + +/** + * Set the value of `autoplay` on the swf. `autoplay` indicates + * that the media should start to play as soon as the page is ready. + * + * @method Flash.prototype.setAutoplay + * @param {boolean} autoplay + * - The value of `autoplay` from the swf. + * - True indicates that the media ashould start as soon as the page loads. + * - False indicates that the media should not start as soon as the page loads. + */ + +/** + * Set the value of `loop` on the swf. `loop` indicates + * that the media should return to the start of the media and continue playing once + * it reaches the end. + * + * @method Flash.prototype.setLoop + * @param {boolean} loop + * - True indicates that playback should seek back to start once + * the end of a media is reached. + * - False indicates that playback should not loop back to the start when the + * end of the media is reached. + */ + +/** + * Set the value of `mediaGroup` on the swf. + * + * @method Flash.prototype.setMediaGroup + * @param {string} mediaGroup + * New value of `mediaGroup` to set on the swf. + */ + +/** + * Set the value of `controller` on the swf. + * + * @method Flash.prototype.setController + * @param {string} controller + * New value the current value of `controller` on the swf. + */ + +/** + * Get the value of `controls` from the swf. `controls` indicates + * whether the native flash controls should be shown or hidden. + * + * @method Flash.prototype.controls + * @return {boolean} + * - The value of `controls` from the swf. + * - True indicates that native controls should be showing. + * - False indicates that native controls should be hidden. + */ + +/** + * Set the value of the `volume` on the swf. `volume` indicates the current + * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and + * so on. + * + * @method Flash.prototype.setVolume + * @param {number} percentAsDecimal + * The volume percent as a decimal. Value will be between 0-1. + */ + +/** + * Set the value of the `muted` on the swf. `muted` indicates that the current + * audio level should be silent. + * + * @method Flash.prototype.setMuted + * @param {boolean} muted + * - True if the audio should be set to silent + * - False otherwise + */ + +/** + * Set the value of `defaultMuted` on the swf. `defaultMuted` indicates + * whether the media should start muted or not. Only changes the default state of the + * media. `muted` and `defaultMuted` can have different values. `muted` indicates the + * current state. + * + * @method Flash.prototype.setDefaultMuted + * @param {boolean} defaultMuted + * - True indicates that the media should start muted. + * - False indicates that the media should not start muted. + */ + /* Flash Support Testing -------------------------------------------------------- */ +/** + * Check if the Flash tech is currently supported. + * + * @return {boolean} + * - True if the flash tech is supported. + * - False otherwise. + */ Flash.isSupported = function() { return Flash.version()[0] >= 10; // return swfobject.hasFlashPlayerVersion('10'); @@ -371,18 +768,24 @@ Flash.isSupported = function() { Tech.withSourceHandlers(Flash); /* - * The default native source handler. - * This simply passes the source to the video element. Nothing fancy. + * Native source handler for flash, simply passes the source to the swf element. + * + * @property {Tech~SourceObject} source + * The source object * - * @param {Object} source The source object - * @param {Flash} tech The instance of the Flash tech + * @property {Flash} tech + * The instance of the Flash tech */ Flash.nativeSourceHandler = {}; /** - * Check if Flash can play the given videotype - * @param {String} type The mimetype to check - * @return {String} 'probably', 'maybe', or '' (empty string) + * Check if the Flash can play the given mime type. + * + * @param {string} type + * The mimetype to check + * + * @return {string} + * 'maybe', or '' (empty string) */ Flash.nativeSourceHandler.canPlayType = function(type) { if (type in Flash.formats) { @@ -392,12 +795,17 @@ Flash.nativeSourceHandler.canPlayType = function(type) { return ''; }; -/* - * Check Flash can handle the source natively +/** + * Check if the media element can handle a source natively. + * + * @param {Tech~SourceObject} source + * The source object + * + * @param {Object} [options] + * Options to be passed to the tech. * - * @param {Object} source The source object - * @param {Object} options The options passed to the tech - * @return {String} 'probably', 'maybe', or '' (empty string) + * @return {string} + * 'maybe', or '' (empty string). */ Flash.nativeSourceHandler.canHandleSource = function(source, options) { let type; @@ -421,28 +829,35 @@ Flash.nativeSourceHandler.canHandleSource = function(source, options) { return Flash.nativeSourceHandler.canPlayType(type); }; -/* - * Pass the source to the flash object - * Adaptive source handlers will have more complicated workflows before passing - * video data to the video element +/** + * Pass the source to the swf. + * + * @param {Tech~SourceObject} source + * The source object * - * @param {Object} source The source object - * @param {Flash} tech The instance of the Flash tech - * @param {Object} options The options to pass to the source + * @param {Flash} tech + * The instance of the Flash tech + * + * @param {Object} [options] + * The options to pass to the source */ Flash.nativeSourceHandler.handleSource = function(source, tech, options) { tech.setSrc(source.src); }; -/* - * Clean up the source handler when disposing the player or switching sources.. - * (no cleanup is needed when supporting the format natively) +/** + * noop for native source handler dispose, as cleanup will happen automatically. */ Flash.nativeSourceHandler.dispose = function() {}; // Register the native source handler Flash.registerSourceHandler(Flash.nativeSourceHandler); +/** + * Flash supported mime types. + * + * @constant {Object} + */ Flash.formats = { 'video/flv': 'FLV', 'video/x-flv': 'FLV', @@ -450,6 +865,10 @@ Flash.formats = { 'video/m4v': 'MP4' }; +/** + * Called when the the swf is "ready", and makes sure that the swf is really + * ready using {@link Flash#checkReady} + */ Flash.onReady = function(currSwf) { const el = Dom.getEl(currSwf); const tech = el && el.tech; @@ -462,8 +881,14 @@ Flash.onReady = function(currSwf) { } }; -// The SWF isn't always ready when it says it is. Sometimes the API functions still need to be added to the object. -// If it's not ready, we set a timeout to check again shortly. +/** + * The SWF isn't always ready when it says it is. Sometimes the API functions still + * need to be added to the object. If it's not ready, we set a timeout to check again + * shortly. + * + * @param {Flash} tech + * The instance of the flash tech to check. + */ Flash.checkReady = function(tech) { // stop worrying if the tech has been disposed if (!tech.el()) { @@ -482,7 +907,15 @@ Flash.checkReady = function(tech) { } }; -// Trigger events from the swf on the player +/** + * Trigger events from the swf on the Flash Tech. + * + * @param {number} swfID + * The id of the swf that had the event + * + * @param {string} eventName + * The name of the event to trigger + */ Flash.onEvent = function(swfID, eventName) { const tech = Dom.getEl(swfID).tech; const args = Array.prototype.slice.call(arguments, 2); @@ -497,7 +930,19 @@ Flash.onEvent = function(swfID, eventName) { }, 1); }; -// Log errors from the swf +/** + * Log errors from the swf on the Flash tech. + * + * @param {number} swfID + * The id of the swf that had an error. + * + * @param {string} The error string + * The error to set on the Flash Tech. + * + * @return {MediaError|undefined} + * - Returns a MediaError when err is 'srcnotfound' + * - Returns undefined otherwise. + */ Flash.onError = function(swfID, err) { const tech = Dom.getEl(swfID).tech; @@ -510,7 +955,12 @@ Flash.onError = function(swfID, err) { tech.error('FLASH: ' + err); }; -// Flash Version Check +/** + * Get the current version of Flash that is in use on the page. + * + * @return {Array} + * an array of versions that are available. + */ Flash.version = function() { let version = '0,0,0'; @@ -531,7 +981,24 @@ Flash.version = function() { return version.split(','); }; -// Flash embedding method. Only used in non-iframe mode +/** + * Only use for non-iframe embeds. + * + * @param {Object} swf + * The videojs-swf object. + * + * @param {Object} flashVars + * Names and values to use as flash option variables. + * + * @param {Object} params + * Style parameters to set on the object. + * + * @param {Object} attributes + * Attributes to set on the element. + * + * @return {Element} + * The embeded Flash DOM element. + */ Flash.embed = function(swf, flashVars, params, attributes) { const code = Flash.getEmbedCode(swf, flashVars, params, attributes); @@ -541,6 +1008,24 @@ Flash.embed = function(swf, flashVars, params, attributes) { return obj; }; +/** + * Only use for non-iframe embeds. + * + * @param {Object} swf + * The videojs-swf object. + * + * @param {Object} flashVars + * Names and values to use as flash option variables. + * + * @param {Object} params + * Style parameters to set on the object. + * + * @param {Object} attributes + * Attributes to set on the element. + * + * @return {Element} + * The embeded Flash DOM element. + */ Flash.getEmbedCode = function(swf, flashVars, params, attributes) { const objTag = ' techTracks.addTrack(e.track); this[`handle${capitalType}TrackRemove_`] = (e) => techTracks.removeTrack(e.track); @@ -141,7 +148,7 @@ class Html5 extends Tech { } /** - * Dispose of html5 media element + * Dispose of `HTML5` media element and remove all tracks. */ dispose() { // Un-ProxyNativeTracks @@ -167,9 +174,10 @@ class Html5 extends Tech { } /** - * Create the component's DOM element + * Create the `Html5` Tech's DOM element. * * @return {Element} + * The element that gets created. */ createEl() { let el = this.options_.tag; @@ -222,13 +230,21 @@ class Html5 extends Tech { } return el; - // jenniisawesome = true; } - // If we're loading the playback object after it has started loading - // or playing the video (often with autoplay on) then the loadstart event - // has already fired and we need to fire it manually because many things - // rely on it. + /** + * This will be triggered if the loadstart event has already fired, before videojs was + * ready. Two known examples of when this can happen are: + * 1. If we're loading the playback object after it has started loading + * 2. The media is already playing the (often with autoplay on) then + * + * This function will fire another loadstart so that videojs can catchup. + * + * @fires Tech#loadstart + * + * @return {undefined} + * returns nothing. + */ handleLateInit_(el) { if (el.networkState === 0 || el.networkState === 3) { // The video element hasn't started loading the source yet @@ -309,6 +325,10 @@ class Html5 extends Tech { }); } + /** + * Add event listeners to native text track events. This adds the native text tracks + * to our emulated {@link TextTrackList}. + */ proxyNativeTextTracks_() { const tt = this.el().textTracks; @@ -330,6 +350,14 @@ class Html5 extends Tech { } } + /** + * Handle any {@link TextTrackList} `change` event. + * + * @param {EventTarget~Event} e + * The `change` event that caused this to run. + * + * @listens TextTrackList#change + */ handleTextTrackChange(e) { const tt = this.textTracks(); @@ -341,23 +369,44 @@ class Html5 extends Tech { }); } + /** + * Handle any {@link TextTrackList} `addtrack` event. + * + * @param {EventTarget~Event} e + * The `addtrack` event that caused this to run. + * + * @listens TextTrackList#addtrack + */ handleTextTrackAdd(e) { this.textTracks().addTrack_(e.track); } + /** + * Handle any {@link TextTrackList} `removetrack` event. + * + * @param {EventTarget~Event} e + * The `removetrack` event that caused this to run. + * + * @listens TextTrackList#removetrack + */ handleTextTrackRemove(e) { this.textTracks().removeTrack_(e.track); } /** - * This is a helper function that is used in removeOldTextTracks_, removeOldAudioTracks_ and - * removeOldVideoTracks_ - * @param {Track[]} techTracks Tracks for this tech - * @param {Track[]} elTracks Tracks for the HTML5 video element + * This function removes any {@link AudioTrack}s, {@link VideoTrack}s, or + * {@link TextTrack}s that are not in the media elements TrackList. + * + * @param {TrackList} techTracks + * HTML5 Tech's TrackList to search through + * + * @param {TrackList} elTracks + * HTML5 media elements TrackList to search trough. + * * @private */ removeOldTracks_(techTracks, elTracks) { - // This will loop over the techTracks and check if they are still used by the HTML5 video element + // This will loop over the techTracks and check if they are still used by the HTML5 media element // If not, they will be removed from the emulated list const removeTracks = []; @@ -388,7 +437,13 @@ class Html5 extends Tech { } } - removeOldTextTracks_() { + /** + * Remove {@link TextTrack}s that dont exist in the native track list from our + * emulated {@link TextTrackList}. + * + * @listens Tech#loadstart + */ + removeOldTextTracks_(e) { const techTracks = this.textTracks(); const elTracks = this.el().textTracks; @@ -396,7 +451,7 @@ class Html5 extends Tech { } /** - * Play for html5 tech + * Called by {@link Player#play} to play using the `Html5` `Tech`. */ play() { const playPromise = this.el_.play(); @@ -409,9 +464,10 @@ class Html5 extends Tech { } /** - * Set current time + * Set current time for the `HTML5` tech. * - * @param {Number} seconds Current time of video + * @param {number} seconds + * Set the current time of the media to this. */ setCurrentTime(seconds) { try { @@ -423,9 +479,10 @@ class Html5 extends Tech { } /** - * Get duration + * Get the current duration of the HTML5 media element. * - * @return {Number} + * @return {number} + * The duration of the media or 0 if there is no duration. */ duration() { // Android Chrome will report duration as Infinity for VOD HLS until after @@ -455,18 +512,20 @@ class Html5 extends Tech { } /** - * Get player width + * Get the current width of the HTML5 media element. * - * @return {Number} + * @return {number} + * The width of the HTML5 media element. */ width() { return this.el_.offsetWidth; } /** - * Get player height + * Get the current height of the HTML5 media element. * - * @return {Number} + * @return {number} + * The heigth of the HTML5 media element. */ height() { return this.el_.offsetHeight; @@ -474,10 +533,13 @@ class Html5 extends Tech { /** * Proxy iOS `webkitbeginfullscreen` and `webkitendfullscreen` into - * `fullscreenchange` event + * `fullscreenchange` event. * * @private - * @method proxyWebkitFullscreen_ + * @fires fullscreenchange + * @listens webkitendfullscreen + * @listens webkitbeginfullscreen + * @listens webkitbeginfullscreen */ proxyWebkitFullscreen_() { if (!('webkitDisplayingFullscreen' in this.el_)) { @@ -502,9 +564,11 @@ class Html5 extends Tech { } /** - * Get if there is fullscreen support + * Check if fullscreen is supported on the current playback device. * - * @return {Boolean} + * @return {boolean} + * - True if fullscreen is supported. + * - False if fullscreen is not supported. */ supportsFullScreen() { if (typeof this.el_.webkitEnterFullScreen === 'function') { @@ -519,7 +583,7 @@ class Html5 extends Tech { } /** - * Request to enter fullscreen + * Request that the `HTML5` Tech enter fullscreen. */ enterFullScreen() { const video = this.el_; @@ -541,17 +605,24 @@ class Html5 extends Tech { } /** - * Request to exit fullscreen + * Request that the `HTML5` Tech exit fullscreen. */ exitFullScreen() { this.el_.webkitExitFullScreen(); } /** - * Get/set video + * A getter/setter for the `Html5` Tech's source object. + * > Note: Please use {@link Html5#setSource} * - * @param {Object=} src Source object - * @return {Object} + * @param {Tech~SourceObject} [src] + * The source object you want to set on the `HTML5` techs element. + * + * @return {Tech~SourceObject|undefined} + * - The current source object when a source is not passed in. + * - undefined when setting + * + * @deprecated Since version 5. */ src(src) { if (src === undefined) { @@ -563,16 +634,20 @@ class Html5 extends Tech { } /** - * Reset the tech. Removes all sources and calls `load`. + * Reset the tech by removing all sources and then calling + * {@link Html5.resetMediaElement}. */ reset() { Html5.resetMediaElement(this.el_); } /** - * Get current source + * Get the current source on the `HTML5` Tech. Falls back to returning the source from + * the HTML5 media element. * - * @return {Object} + * @return {Tech~SourceObject} + * The current source object from the HTML5 tech. With a fallback to the + * elements source. */ currentSrc() { if (this.currentSource_) { @@ -582,22 +657,29 @@ class Html5 extends Tech { } /** - * Set controls attribute + * Set controls attribute for the HTML5 media Element. * - * @param {String} val Value for controls attribute + * @param {string} val + * Value to set the controls attribute to */ setControls(val) { this.el_.controls = !!val; } /** - * Creates and returns a text track object + * Create and returns a remote {@link TextTrack} object. + * + * @param {string} kind + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata) + * + * @param {string} [label] + * Label to identify the text track * - * @param {String} kind Text track kind (subtitles, captions, descriptions - * chapters and metadata) - * @param {String=} label Label to identify the text track - * @param {String=} language Two letter language abbreviation - * @return {TextTrackObject} + * @param {string} [language] + * Two letter language abbreviation + * + * @return {TextTrack} + * The TextTrack that gets created. */ addTextTrack(kind, label, language) { if (!this.featuresNativeTextTracks) { @@ -611,8 +693,29 @@ class Html5 extends Tech { * Creates either native TextTrack or an emulated TextTrack depending * on the value of `featuresNativeTextTracks` * - * @param {Object} options The object should contain values for - * kind, language, label and src (location of the WebVTT file) + * @param {Object} options + * The object should contain the options to intialize the TextTrack with. + * + * @param {string} [options.kind] + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata). + * + * @param {string} [options.label]. + * Label to identify the text track + * + * @param {string} [options.language] + * Two letter language abbreviation. + * + * @param {boolean} [options.default] + * Default this track to on. + * + * @param {string} [options.id] + * The internal id to assign this track. + * + * @param {string} [options.src] + * A source url for the track. + * + * @return {HTMLTrackElement} + * The track element that gets created. */ createRemoteTextTrack(options) { if (!this.featuresNativeTextTracks) { @@ -665,9 +768,10 @@ class Html5 extends Tech { } /** - * Remove remote text track from TextTrackList object + * Remove remote `TextTrack` from `TextTrackList` object * - * @param {TextTrackObject} track Texttrack object to remove + * @param {TextTrack} track + * `TextTrack` object to remove */ removeRemoteTextTrack(track) { super.removeRemoteTextTrack(track); @@ -684,13 +788,12 @@ class Html5 extends Tech { } } } - } /* HTML5 Support Testing ---------------------------------------------------- */ /** - * Element for testing browser HTML5 video capabilities + * Element for testing browser HTML5 media capabilities * * @type {Element} * @constant @@ -705,9 +808,11 @@ track.label = 'English'; Html5.TEST_VID.appendChild(track); /** - * Check if HTML5 video is supported by this browser/device + * Check if HTML5 media is supported by this browser/device. * - * @return {Boolean} + * @return {boolean} + * - True if HTML5 media is supported. + * - False if HTML5 media is not supported. */ Html5.isSupported = function() { // IE9 with no Media Player is a LIAR! (#984) @@ -725,7 +830,9 @@ Html5.isSupported = function() { * Volume cannot be changed in a lot of mobile devices. * Specifically, it can't be changed from 1 on iOS. * - * @return {Boolean} + * @return {boolean} + * - True if volume can be controlled + * - False otherwise */ Html5.canControlVolume = function() { // IE will error if Windows Media Player not installed #3315 @@ -740,9 +847,11 @@ Html5.canControlVolume = function() { }; /** - * Check if playbackRate is supported in this browser/device. + * Check if the playback rate can be changed in this browser/device. * - * @return {Boolean} + * @return {boolean} + * - True if playback rate can be controlled + * - False otherwise */ Html5.canControlPlaybackRate = function() { // Playback rate API is implemented in Android Chrome, but doesn't do anything @@ -762,9 +871,11 @@ Html5.canControlPlaybackRate = function() { }; /** - * Check to see if native text tracks are supported by this browser/device + * Check to see if native `TextTrack`s are supported by this browser/device. * - * @return {Boolean} + * @return {boolean} + * - True if native `TextTrack`s are supported. + * - False otherwise */ Html5.supportsNativeTextTracks = function() { let supportsTextTracks; @@ -789,9 +900,11 @@ Html5.supportsNativeTextTracks = function() { }; /** - * Check to see if native video tracks are supported by this browser/device + * Check to see if native `VideoTrack`s are supported by this browser/device * - * @return {Boolean} + * @return {boolean} + * - True if native `VideoTrack`s are supported. + * - False otherwise */ Html5.supportsNativeVideoTracks = function() { const supportsVideoTracks = !!Html5.TEST_VID.videoTracks; @@ -800,9 +913,11 @@ Html5.supportsNativeVideoTracks = function() { }; /** - * Check to see if native audio tracks are supported by this browser/device + * Check to see if native `AudioTrack`s are supported by this browser/device * - * @return {Boolean} + * @return {boolean} + * - True if native `AudioTrack`s are supported. + * - False otherwise */ Html5.supportsNativeAudioTracks = function() { const supportsAudioTracks = !!Html5.TEST_VID.audioTracks; @@ -842,64 +957,83 @@ Html5.Events = [ ]; /** - * Set the tech's volume control support status + * Boolean indicating whether the `Tech` supports volume control. * - * @type {Boolean} + * @type {boolean} + * @default {@link Html5.canControlVolume} */ Html5.prototype.featuresVolumeControl = Html5.canControlVolume(); /** - * Set the tech's playbackRate support status + * Boolean indicating whether the `Tech` supports changing the speed at which the media + * plays. Examples: + * - Set player to play 2x (twice) as fast + * - Set player to play 0.5x (half) as fast * - * @type {Boolean} + * @type {boolean} + * @default {@link Html5.canControlPlaybackRate} */ Html5.prototype.featuresPlaybackRate = Html5.canControlPlaybackRate(); /** - * Set the tech's status on moving the video element. - * In iOS, if you move a video element in the DOM, it breaks video playback. + * Boolean indicating whether the `HTML5` tech currently supports the media element + * moving in the DOM. iOS breaks if you move the media element, so this is set this to + * false there. Everywhere else this should be true. * - * @type {Boolean} + * @type {boolean} + * @default */ Html5.prototype.movingMediaElementInDOM = !browser.IS_IOS; +// TODO: Previous comment: No longer appears to be used. Can probably be removed. +// Is this true? /** - * Set the the tech's fullscreen resize support status. - * HTML video is able to automatically resize when going to fullscreen. - * (No longer appears to be used. Can probably be removed.) + * Boolean indicating whether the `HTML5` tech currently supports automatic media resize + * when going into fullscreen. + * + * @type {boolean} + * @default */ Html5.prototype.featuresFullscreenResize = true; /** - * Set the tech's progress event support status - * (this disables the manual progress events of the Tech) + * Boolean indicating whether the `HTML5` tech currently supports the progress event. + * If this is false, manual `progress` events will be triggred instead. + * + * @type {boolean} + * @default */ Html5.prototype.featuresProgressEvents = true; /** - * Set the tech's timeupdate event support status - * (this disables the manual timeupdate events of the Tech) + * Boolean indicating whether the `HTML5` tech currently supports the timeupdate event. + * If this is false, manual `timeupdate` events will be triggred instead. + * + * @default */ Html5.prototype.featuresTimeupdateEvents = true; /** - * Sets the tech's status on native text track support + * Boolean indicating whether the `HTML5` tech currently supports native `TextTrack`s. * - * @type {Boolean} + * @type {boolean} + * @default {@link Html5.supportsNativeTextTracks} */ Html5.prototype.featuresNativeTextTracks = Html5.supportsNativeTextTracks(); /** - * Sets the tech's status on native text track support + * Boolean indicating whether the `HTML5` tech currently supports native `VideoTrack`s. * - * @type {Boolean} + * @type {boolean} + * @default {@link Html5.supportsNativeVideoTracks} */ Html5.prototype.featuresNativeVideoTracks = Html5.supportsNativeVideoTracks(); /** - * Sets the tech's status on native audio track support + * Boolean indicating whether the `HTML5` tech currently supports native `AudioTrack`s. * - * @type {Boolean} + * @type {boolean} + * @default {@link Html5.supportsNativeAudioTracks} */ Html5.prototype.featuresNativeAudioTracks = Html5.supportsNativeAudioTracks(); @@ -946,7 +1080,7 @@ Html5.unpatchCanPlayType = function() { return r; }; -// by default, patch the video element +// by default, patch the media element Html5.patchCanPlayType(); Html5.disposeMediaElement = function(el) { @@ -1013,172 +1147,304 @@ Html5.resetMediaElement = function(el) { // Wrap native properties with a getter [ /** - * Paused for html5 tech + * Get the value of `paused` from the media element. `paused` indicates whether the media element + * is currently paused or not. * * @method Html5.prototype.paused - * @return {Boolean} + * @return {boolean} + * The value of `paused` from the media element. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-paused} */ 'paused', + /** - * Get current time + * Get the value of `currentTime` from the media element. `currentTime` indicates + * the current second that the media is at in playback. * * @method Html5.prototype.currentTime - * @return {Number} + * @return {number} + * The value of `currentTime` from the media element. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-currenttime} */ 'currentTime', + /** - * Get a TimeRange object that represents the intersection - * of the time ranges for which the user agent has all - * relevant media + * Get the value of `buffered` from the media element. `buffered` is a `TimeRange` + * object that represents the parts of the media that are already downloaded and + * available for playback. * - * @return {TimeRangeObject} * @method Html5.prototype.buffered + * @return {TimeRange} + * The value of `buffered` from the media element. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-buffered} */ 'buffered', + /** - * Get volume level + * Get the value of `volume` from the media element. `volume` indicates + * the current playback volume of audio for a media. `volume` will be a value from 0 + * (silent) to 1 (loudest and default). * - * @return {Number} * @method Html5.prototype.volume + * @return {number} + * The value of `volume` from the media element. Value will be between 0-1. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume} */ 'volume', + /** - * Get if muted + * Get the value of `muted` from the media element. `muted` indicates + * that the volume for the media should be set to silent. This does not actually change + * the `volume` attribute. * - * @return {Boolean} * @method Html5.prototype.muted + * @return {boolean} + * - True if the value of `volume` should be ignored and the audio set to silent. + * - False if the value of `volume` should be used. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted} */ 'muted', + /** - * Get poster + * Get the value of `poster` from the media element. `poster` indicates + * that the url of an image file that can/will be shown when no media data is available. * - * @return {String} * @method Html5.prototype.poster + * @return {string} + * The value of `poster` from the media element. Value will be a url to an + * image. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-video-poster} */ 'poster', + /** - * Get preload attribute + * Get the value of `preload` from the media element. `preload` indicates + * what should download before the media is interacted with. It can have the following + * values: + * - none: nothing should be downloaded + * - metadata: poster and the first few frames of the media may be downloaded to get + * media dimensions and other metadata + * - auto: allow the media and metadata for the media to be downloaded before + * interaction * - * @return {String} * @method Html5.prototype.preload + * @return {string} + * The value of `preload` from the media element. Will be 'none', 'metadata', + * or 'auto'. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload} */ 'preload', + /** - * Get autoplay attribute + * Get the value of `autoplay` from the media element. `autoplay` indicates + * that the media should start to play as soon as the page is ready. * - * @return {String} * @method Html5.prototype.autoplay + * @return {boolean} + * - The value of `autoplay` from the media element. + * - True indicates that the media should start as soon as the page loads. + * - False indicates that the media should not start as soon as the page loads. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay} */ 'autoplay', + /** - * Get controls attribute + * Get the value of `controls` from the media element. `controls` indicates + * whether the native media controls should be shown or hidden. * - * @return {String} * @method Html5.prototype.controls + * @return {boolean} + * - The value of `controls` from the media element. + * - True indicates that native controls should be showing. + * - False indicates that native controls should be hidden. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-controls} */ 'controls', + /** - * Get loop attribute + * Get the value of `loop` from the media element. `loop` indicates + * that the media should return to the start of the media and continue playing once + * it reaches the end. * - * @return {String} * @method Html5.prototype.loop + * @return {boolean} + * - The value of `loop` from the media element. + * - True indicates that playback should seek back to start once + * the end of a media is reached. + * - False indicates that playback should not loop back to the start when the + * end of the media is reached. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop} */ 'loop', + /** - * Get error value + * Get the value of the `error` from the media element. `error` indicates any + * MediaError that may have occured during playback. If error returns null there is no + * current error. * - * @return {String} * @method Html5.prototype.error + * @return {MediaError|null} + * The value of `error` from the media element. Will be `MediaError` if there + * is a current error and null otherwise. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-error} */ 'error', + /** - * Get whether or not the player is in the "seeking" state + * Get the value of `seeking` from the media element. `seeking` indicates whether the + * media is currently seeking to a new position or not. * - * @return {Boolean} * @method Html5.prototype.seeking + * @return {boolean} + * - The value of `seeking` from the media element. + * - True indicates that the media is currently seeking to a new position. + * - Flase indicates that the media is not seeking to a new position at this time. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seeking} */ 'seeking', + /** - * Get a TimeRanges object that represents the - * ranges of the media resource to which it is possible - * for the user agent to seek. + * Get the value of `seekable` from the media element. `seekable` returns a + * `TimeRange` object indicating ranges of time that can currently be `seeked` to. * - * @return {TimeRangeObject} * @method Html5.prototype.seekable + * @return {TimeRange} + * The value of `seekable` from the media element. A `TimeRange` object + * indicating the current ranges of time that can be seeked to. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seekable} */ 'seekable', + /** - * Get if video ended + * Get the value of `ended` from the media element. `ended` indicates whether + * the media has reached the end or not. * - * @return {Boolean} * @method Html5.prototype.ended + * @return {boolean} + * - The value of `ended` from the media element. + * - True indicates that the media has ended. + * - False indicates that the media has not ended. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended} */ 'ended', + /** - * Get the value of the muted content attribute - * This attribute has no dynamic effect, it only - * controls the default state of the element + * Get the value of `defaultMuted` from the media element. `defaultMuted` indicates + * whether the media should start muted or not. Only changes the default state of the + * media. `muted` and `defaultMuted` can have different values. `muted` indicates the + * current state. * - * @return {Boolean} * @method Html5.prototype.defaultMuted + * @return {boolean} + * - The value of `defaultMuted` from the media element. + * - True indicates that the media should start muted. + * - False indicates that the media should not start muted + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted} */ 'defaultMuted', + /** - * Get desired speed at which the media resource is to play + * Get the value of `playbackRate` from the media element. `playbackRate` indicates + * the rate at which the media is currently playing back. Examples: + * - if playbackRate is set to 2, media will play twice as fast. + * - if playbackRate is set to 0.5, media will play half as fast. * - * @return {Number} * @method Html5.prototype.playbackRate + * @return {number} + * The value of `playbackRate` from the media element. A number indicating + * the current playback speed of the media, where 1 is normal speed. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate} */ 'playbackRate', + /** - * Returns a TimeRanges object that represents the ranges of the - * media resource that the user agent has played. - * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-played + * Get the value of `played` from the media element. `played` returns a `TimeRange` + * object representing points in the media timeline that have been played. * - * @return {TimeRangeObject} the range of points on the media - * timeline that has been reached through - * normal playback * @method Html5.prototype.played + * @return {TimeRange} + * The value of `played` from the media element. A `TimeRange` object indicating + * the ranges of time that have been played. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-played} */ 'played', + /** - * Get the current state of network activity for the element, from - * the list below - * - NETWORK_EMPTY (numeric value 0) - * - NETWORK_IDLE (numeric value 1) - * - NETWORK_LOADING (numeric value 2) - * - NETWORK_NO_SOURCE (numeric value 3) - * - * @return {Number} + * Get the value of `networkState` from the media element. `networkState` indicates + * the current network state. It returns an enumeration from the following list: + * - 0: NETWORK_EMPTY + * - 1: NEWORK_IDLE + * - 2: NETWORK_LOADING + * - 3: NETWORK_NO_SOURCE + * * @method Html5.prototype.networkState + * @return {number} + * The value of `networkState` from the media element. This will be a number + * from the list in the description. + * + * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-networkstate} */ 'networkState', + /** - * Get a value that expresses the current state of the element - * with respect to rendering the current playback position, from - * the codes in the list below - * - HAVE_NOTHING (numeric value 0) - * - HAVE_METADATA (numeric value 1) - * - HAVE_CURRENT_DATA (numeric value 2) - * - HAVE_FUTURE_DATA (numeric value 3) - * - HAVE_ENOUGH_DATA (numeric value 4) - * - * @return {Number} + * Get the value of `readyState` from the media element. `readyState` indicates + * the current state of the media element. It returns an enumeration from the + * following list: + * - 0: HAVE_NOTHING + * - 1: HAVE_METADATA + * - 2: HAVE_CURRENT_DATA + * - 3: HAVE_FUTURE_DATA + * - 4: HAVE_ENOUGH_DATA + * * @method Html5.prototype.readyState + * @return {number} + * The value of `readyState` from the media element. This will be a number + * from the list in the description. + * + * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#ready-states} */ 'readyState', + /** - * Get width of video + * Get the value of `videoWidth` from the video element. `videoWidth` indicates + * the current width of the video in css pixels. * - * @return {Number} * @method Html5.prototype.videoWidth + * @return {number} + * The value of `videoWidth` from the video element. This will be a number + * in css pixels. + * + * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth} */ 'videoWidth', + /** - * Get height of video + * Get the value of `videoHeight` from the video element. `videoHeigth` indicates + * the current height of the video in css pixels. * - * @return {Number} * @method Html5.prototype.videoHeight + * @return {number} + * The value of `videoHeight` from the video element. This will be a number + * in css pixels. + * + * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth} */ 'videoHeight' ].forEach(function(prop) { @@ -1191,60 +1457,116 @@ Html5.resetMediaElement = function(el) { // set + toTitleCase(name) [ /** - * Set volume level + * Set the value of `volume` on the media element. `volume` indicates the current + * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and + * so on. * - * @param {Number} percentAsDecimal Volume percent as a decimal * @method Html5.prototype.setVolume + * @param {number} percentAsDecimal + * The volume percent as a decimal. Valid range is from 0-1. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume} */ 'volume', + /** - * Set muted + * Set the value of `muted` on the media element. `muted` indicates the current + * audio level should be silent. * - * @param {Boolean} muted If player is to be muted or note * @method Html5.prototype.setMuted + * @param {boolean} muted + * - True if the audio should be set to silent + * - False otherwise + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted} */ 'muted', + /** - * Set video source + * Set the value of `src` on the media element. `src` indicates the current + * {@link Tech~SourceObject} for the media. * - * @param {Object} src Source object - * @deprecated since version 5 * @method Html5.prototype.setSrc + * @param {Tech~SourceObject} src + * The source object to set as the current source. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-src} */ 'src', + /** - * Set poster + * Set the value of `poster` on the media element. `poster` is the url to + * an image file that can/will be shown when no media data is available. * - * @param {String} val URL to poster image * @method Html5.prototype.setPoster + * @param {string} poster + * The url to an image that should be used as the `poster` for the media + * element. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-poster} */ 'poster', + /** - * Set preload attribute + * Set the value of `preload` on the media element. `preload` indicates + * what should download before the media is interacted with. It can have the following + * values: + * - none: nothing should be downloaded + * - metadata: poster and the first few frames of the media may be downloaded to get + * media dimensions and other metadata + * - auto: allow the media and metadata for the media to be downloaded before + * interaction + * + * @method Html5.prototype.setPreload + * @param {string} preload + * The value of `preload` to set on the media element. Must be 'none', 'metadata', + * or 'auto'. * - * @param {String} val Value for the preload attribute - * @method Htm5.prototype.setPreload + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload} */ 'preload', + /** - * Set autoplay attribute + * Set the value of `autoplay` on the media element. `autoplay` indicates + * that the media should start to play as soon as the page is ready. * - * @param {Boolean} autoplay Value for the autoplay attribute - * @method setAutoplay + * @method Html5.prototype.setAutoplay + * @param {boolean} autoplay + * - True indicates that the media should start as soon as the page loads. + * - False indicates that the media should not start as soon as the page loads. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay} */ 'autoplay', + /** - * Set loop attribute + * Set the value of `loop` on the media element. `loop` indicates + * that the media should return to the start of the media and continue playing once + * it reaches the end. * - * @param {Boolean} loop Value for the loop attribute * @method Html5.prototype.setLoop + * @param {boolean} loop + * - True indicates that playback should seek back to start once + * the end of a media is reached. + * - False indicates that playback should not loop back to the start when the + * end of the media is reached. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop} */ 'loop', + /** - * Set desired speed at which the media resource is to play + * Set the value of `playbackRate` on the media element. `playbackRate` indicates + * the rate at which the media should play back. Examples: + * - if playbackRate is set to 2, media will play twice as fast. + * - if playbackRate is set to 0.5, media will play half as fast. * - * @param {Number} val Speed at which the media resource is to play * @method Html5.prototype.setPlaybackRate + * @return {number} + * The value of `playbackRate` from the media element. A number indicating + * the current playback speed of the media, where 1 is normal speed. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate} */ 'playbackRate' ].forEach(function(prop) { @@ -1256,15 +1578,20 @@ Html5.resetMediaElement = function(el) { // wrap native functions with a function [ /** - * Pause for html5 tech + * A wrapper around the media elements `pause` function. This will call the `HTML5` + * media elements `pause` function. * * @method Html5.prototype.pause + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-pause} */ 'pause', + /** - * Load media into player + * A wrapper around the media elements `load` function. This will call the `HTML5`s + * media element `load` function. * * @method Html5.prototype.load + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-load} */ 'load' ].forEach(function(prop) { @@ -1273,23 +1600,27 @@ Html5.resetMediaElement = function(el) { }; }); -// Add Source Handler pattern functions to this tech Tech.withSourceHandlers(Html5); /** - * The default native source handler. - * This simply passes the source to the video element. Nothing fancy. + * Native source handler for Html5, simply passes the source to the media element. + * + * @proprety {Tech~SourceObject} source + * The source object * - * @param {Object} source The source object - * @param {Html5} tech The instance of the HTML5 tech + * @proprety {Html5} tech + * The instance of the HTML5 tech. */ Html5.nativeSourceHandler = {}; /** - * Check if the video element can play the given videotype + * Check if the media element can play the given mime type. * - * @param {String} type The mimetype to check - * @return {String} 'probably', 'maybe', or '' (empty string) + * @param {string} type + * The mimetype to check + * + * @return {string} + * 'probably', 'maybe', or '' (empty string) */ Html5.nativeSourceHandler.canPlayType = function(type) { // IE9 on Windows 7 without MediaPlayer throws an error here @@ -1302,11 +1633,16 @@ Html5.nativeSourceHandler.canPlayType = function(type) { }; /** - * Check if the video element can handle the source natively + * Check if the media element can handle a source natively. + * + * @param {Tech~SourceObject} source + * The source object + * + * @param {Object} [options] + * Options to be passed to the tech. * - * @param {Object} source The source object - * @param {Object} options The options passed to the tech - * @return {String} 'probably', 'maybe', or '' (empty string) + * @return {string} + * 'probably', 'maybe', or '' (empty string). */ Html5.nativeSourceHandler.canHandleSource = function(source, options) { @@ -1325,21 +1661,23 @@ Html5.nativeSourceHandler.canHandleSource = function(source, options) { }; /** - * Pass the source to the video element - * Adaptive source handlers will have more complicated workflows before passing - * video data to the video element + * Pass the source to the native media element. * - * @param {Object} source The source object - * @param {Html5} tech The instance of the Html5 tech - * @param {Object} options The options to pass to the source + * @param {Tech~SourceObject} source + * The source object + * + * @param {Html5} tech + * The instance of the Html5 tech + * + * @param {Object} [options] + * The options to pass to the source */ Html5.nativeSourceHandler.handleSource = function(source, tech, options) { tech.setSrc(source.src); }; -/* - * Clean up the source handler when disposing the player or switching sources.. - * (no cleanup is needed when supporting the format natively) +/** + * A noop for the native dispose function, as cleanup is not needed. */ Html5.nativeSourceHandler.dispose = function() {}; diff --git a/src/js/tech/loader.js b/src/js/tech/loader.js index 0675e4abcb..35814fc8d3 100644 --- a/src/js/tech/loader.js +++ b/src/js/tech/loader.js @@ -6,17 +6,25 @@ import Tech from './tech.js'; import toTitleCase from '../utils/to-title-case.js'; /** - * The Media Loader is the component that decides which playback technology to load - * when the player is initialized. + * The `MediaLoader` is the `Component` that decides which playback technology to load + * when a player is initialized. * - * @param {Object} player Main Player - * @param {Object=} options Object of option names and values - * @param {Function=} ready Ready callback function * @extends Component - * @class MediaLoader */ class MediaLoader extends Component { + /** + * Create an instance of this class. + * + * @param {Player} player + * The `Player` that this class should attach to. + * + * @param {Object} [options] + * The key/value stroe of player options. + * + * @param {Component~ReadyCallback} [ready] + * The function that is run when this component is ready. + */ constructor(player, options, ready) { super(player, options, ready); diff --git a/src/js/tech/tech.js b/src/js/tech/tech.js index ed9fafdd64..991d84246d 100644 --- a/src/js/tech/tech.js +++ b/src/js/tech/tech.js @@ -1,7 +1,5 @@ /** * @file tech.js - * Media Technology Controller - Base class for media playback - * technology controllers like Flash and HTML5 */ import Component from '../component'; @@ -20,6 +18,48 @@ import MediaError from '../media-error.js'; import window from 'global/window'; import document from 'global/document'; +/** + * An Object containing a structure like: `{src: 'url', type: 'mimetype'}` or string + * that just contains the src url alone. + * + * ``` js + * var SourceObject = { + * src: 'http://example.com/some-video.mp4', + * type: 'video/mp4' + * }; + * var SourceString = 'http://example.com/some-video.mp4'; + * ``` + * + * @typedef {Object|string} Tech~SourceObject + * + * @property {string} src + * The url to the source + * + * @property {string} type + * The mime type of the source + */ + +/** + * A function used by {@link Tech} to create a new {@link TextTrack}. + * + * @param {Tech} self + * An instance of the Tech class. + * + * @param {string} kind + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata) + * + * @param {string} [label] + * Label to identify the text track + * + * @param {string} [language] + * Two letter language abbreviation + * + * @param {Object} [options={}] + * An object with additional text track options + * + * @return {TextTrack} + * The text track that was created. + */ function createTrackHelper(self, kind, label, language, options = {}) { const tracks = self.textTracks(); @@ -41,15 +81,22 @@ function createTrackHelper(self, kind, label, language, options = {}) { } /** - * Base class for media (HTML5 Video, Flash) controllers + * This is the base class for media playback technology controllers, such as + * {@link Flash} and {@link HTML5} * - * @param {Object=} options Options object - * @param {Function=} ready Ready callback function * @extends Component - * @class Tech */ class Tech extends Component { + /** + * Create an instance of this Tech. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} ready + * Callback function to call when the `HTML5` Tech is ready. + */ constructor(options = {}, ready = function() {}) { // we don't want the tech to report user activity automatically. // This is done manually in addControlsListeners @@ -105,12 +152,11 @@ class Tech extends Component { /* Fallbacks for unsupported event types ================================================================================ */ - // Manually trigger progress events based on changes to the buffered amount - // Many flash players and older HTML5 browsers don't send progress or progress-like events + /** - * Turn on progress events + * Polyfill the `progress` event for browsers that don't support it natively. * - * @method manualProgressOn + * @see {@link Tech#trackProgress} */ manualProgressOn() { this.on('durationchange', this.onDurationChange); @@ -122,9 +168,8 @@ class Tech extends Component { } /** - * Turn off progress events - * - * @method manualProgressOff + * Turn off the polyfill for `progress` events that was created in + * {@link Tech#manualProgressOn} */ manualProgressOff() { this.manualProgress = false; @@ -134,11 +179,19 @@ class Tech extends Component { } /** - * Track progress + * This is used to trigger a `progress` event when the buffered percent changes. It + * sets an interval function that will be called every 500 milliseconds to check if the + * buffer end percent has changed. + * + * > This function is called by {@link Tech#manualProgressOn} + * + * @param {EventTarget~Event} event + * The `ready` event that caused this to run. * - * @method trackProgress + * @listens Tech#ready + * @fires Tech#progress */ - trackProgress() { + trackProgress(event) { this.stopTrackingProgress(); this.progressInterval = this.setInterval(Fn.bind(this, function() { // Don't trigger unless buffered amount is greater than last time @@ -146,6 +199,12 @@ class Tech extends Component { const numBufferedPercent = this.bufferedPercent(); if (this.bufferedPercent_ !== numBufferedPercent) { + /** + * See {@link Player#progress} + * + * @event Tech#progress + * @type {EventTarget~Event} + */ this.trigger('progress'); } @@ -158,47 +217,54 @@ class Tech extends Component { } /** - * Update duration + * Update our internal duration on a `durationchange` event by calling + * {@link Tech#duration}. * - * @method onDurationChange + * @param {EventTarget~Event} event + * The `durationchange` event that caused this to run. + * + * @listens Tech#durationchange */ - onDurationChange() { + onDurationChange(event) { this.duration_ = this.duration(); } /** - * Create and get TimeRange object for buffering + * Get and create a `TimeRange` object for buffering. * - * @return {TimeRangeObject} - * @method buffered + * @return {TimeRange} + * The time range object that was created. */ buffered() { return createTimeRange(0, 0); } /** - * Get buffered percent + * Get the percentage of the current video that is currently buffered. + * + * @return {number} + * A number from 0 to 1 that represents the decimal percentage of the + * video that is buffered. * - * @return {Number} - * @method bufferedPercent */ bufferedPercent() { return bufferedPercent(this.buffered(), this.duration_); } /** - * Stops tracking progress by clearing progress interval - * - * @method stopTrackingProgress + * Turn off the polyfill for `progress` events that was created in + * {@link Tech#manualProgressOn} + * Stop manually tracking progress events by clearing the interval that was set in + * {@link Tech#trackProgress}. */ stopTrackingProgress() { this.clearInterval(this.progressInterval); } /** - * Set event listeners for on play and pause and tracking current time + * Polyfill the `timeupdate` event for browsers that don't support it. * - * @method manualTimeUpdatesOn + * @see {@link Tech#trackCurrentTime} */ manualTimeUpdatesOn() { this.manualTimeUpdates = true; @@ -208,9 +274,8 @@ class Tech extends Component { } /** - * Remove event listeners for on play and pause and tracking current time - * - * @method manualTimeUpdatesOff + * Turn off the polyfill for `timeupdate` events that was created in + * {@link Tech#manualTimeUpdatesOn} */ manualTimeUpdatesOff() { this.manualTimeUpdates = false; @@ -220,15 +285,23 @@ class Tech extends Component { } /** - * Tracks current time + * Sets up an interval function to track current time and trigger `timeupdate` every + * 250 milliseconds. * - * @method trackCurrentTime + * @listens Tech#play + * @triggers Tech#timeupdate */ trackCurrentTime() { if (this.currentTimeInterval) { this.stopTrackingCurrentTime(); } this.currentTimeInterval = this.setInterval(function() { + /** + * Triggered at an interval of 250ms to indicated that time is passing in the video. + * + * @event Tech#timeupdate + * @type {EventTarget~Event} + */ this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15 @@ -236,9 +309,10 @@ class Tech extends Component { } /** - * Turn off play progress tracking (when paused or dragging) + * Stop the interval function created in {@link Tech#trackCurrentTime} so that the + * `timeupdate` event is no longer triggered. * - * @method stopTrackingCurrentTime + * @listens {Tech#pause} */ stopTrackingCurrentTime() { this.clearInterval(this.currentTimeInterval); @@ -249,9 +323,10 @@ class Tech extends Component { } /** - * Turn off any manual progress or timeupdate tracking + * Turn off all event polyfills, clear the `Tech`s {@link AudioTrackList}, + * {@link VideoTrackList}, and {@link TextTrackList}, and dispose of this Tech. * - * @method dispose + * @fires Component#dispose */ dispose() { @@ -271,15 +346,14 @@ class Tech extends Component { } /** - * clear out a track list, or multiple track lists + * Clear out a single `TrackList` or an array of `TrackLists` given their names. * - * Note: Techs without source handlers should call this between - * sources for video & audio tracks, as usually you don't want - * to use them between tracks and we have no automatic way to do - * it for you + * > Note: Techs without source handlers should call this between sources for `video` + * & `audio` tracks. You don't want to use them between tracks! * - * @method clearTracks - * @param {Array|String} types type(s) of track lists to empty + * @param {string[]|string} types + * TrackList names to clear, valid names are `video`, `audio`, and + * `text`. */ clearTracks(types) { types = [].concat(types); @@ -302,8 +376,6 @@ class Tech extends Component { /** * Remove any TextTracks added via addRemoteTextTrack that are * flagged for automatic garbage collection - * - * @method cleanupAutoTextTracks */ cleanupAutoTextTracks() { const list = this.autoRemoteTextTracks_ || []; @@ -317,20 +389,20 @@ class Tech extends Component { } /** - * Reset the tech. Removes all sources and resets readyState. + * Reset the tech, which will removes all sources and reset the internal readyState. * - * @method reset + * @abstract */ reset() {} /** - * When invoked without an argument, returns a MediaError object - * representing the current error state of the player or null if - * there is no error. When invoked with an argument, set the current - * error state of the player. - * @param {MediaError=} err Optional an error object - * @return {MediaError} the current error object or null - * @method error + * Get or set an error on the Tech. + * + * @param {MediaError} [err] + * Error to set on the Tech + * + * @return {MediaError|null} + * The current error object on the tech, or null if there isn't one. */ error(err) { if (err !== undefined) { @@ -341,13 +413,14 @@ class Tech extends Component { } /** - * Return the time ranges that have been played through for the - * current source. This implementation is incomplete. It does not - * track the played time ranges, only whether the source has played - * at all or not. - * @return {TimeRangeObject} a single time range if this video has - * played or an empty set of ranges if not. - * @method played + * Returns the `TimeRange`s that have been played through for the current source. + * + * > NOTE: This implementation is incomplete. It does not track the played `TimeRange`. + * It only checks wether the source has played at all or not. + * + * @return {TimeRange} + * - A single time range if this video has played + * - An empty set of ranges if not. */ played() { if (this.hasStarted_) { @@ -357,24 +430,39 @@ class Tech extends Component { } /** - * Set current time + * Causes a manual time update to occur if {@link Tech#manualTimeUpdatesOn} was + * previously called. * - * @method setCurrentTime + * @fires Tech#timeupdate */ setCurrentTime() { // improve the accuracy of manual timeupdates if (this.manualTimeUpdates) { + /** + * A manual `timeupdate` event. + * + * @event Tech#timeupdate + * @type {EventTarget~Event} + */ this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); } } /** - * Initialize texttrack listeners + * Turn on listeners for {@link TextTrackList} events. This adds + * {@link EventTarget~EventListeners} for `texttrackchange`, `addtrack` and + * `removetrack`. * - * @method initTextTrackListeners + * @fires Tech#texttrackchange */ initTextTrackListeners() { const textTrackListChanges = Fn.bind(this, function() { + /** + * Triggered when tracks are added or removed on the Tech {@link TextTrackList} + * + * @event Tech#texttrackchange + * @type {EventTarget~Event} + */ this.trigger('texttrackchange'); }); @@ -394,14 +482,29 @@ class Tech extends Component { } /** - * Initialize audio and video track listeners + * Turn on listeners for {@link VideoTrackList} and {@link {AudioTrackList} events. + * This adds {@link EventTarget~EventListeners} for `addtrack`, and `removetrack`. * - * @method initTrackListeners + * @fires Tech#audiotrackchange + * @fires Tech#videotrackchange */ initTrackListeners() { const trackTypes = ['video', 'audio']; trackTypes.forEach((type) => { + /** + * Triggered when tracks are added or removed on the Tech {@link AudioTrackList} + * + * @event Tech#audiotrackchange + * @type {EventTarget~Event} + */ + + /** + * Triggered when tracks are added or removed on the Tech {@link VideoTrackList} + * + * @event Tech#videotrackchange + * @type {EventTarget~Event} + */ const trackListChanges = () => { this.trigger(`${type}trackchange`); }; @@ -419,9 +522,11 @@ class Tech extends Component { } /** - * Add vtt.js if necessary + * Emulate TextTracks using vtt.js if necessary * - * @private + * @fires Tech#vttjsloaded + * @fires Tech#vttjserror + * @fires Tech#texttrackchange */ addWebVttScript_() { if (!window.WebVTT && this.el().parentNode !== null && this.el().parentNode !== undefined) { @@ -429,9 +534,21 @@ class Tech extends Component { script.src = this.options_['vtt.js'] || '../node_modules/videojs-vtt.js/dist/vtt.js'; script.onload = () => { + /** + * Fired when vtt.js is loaded. + * + * @event Tech#vttjsloaded + * @type {EventTarget~Event} + */ this.trigger('vttjsloaded'); }; script.onerror = () => { + /** + * Fired when vtt.js was not loaded due to an error + * + * @event Tech#vttjsloaded + * @type {EventTarget~Event} + */ this.trigger('vttjserror'); }; this.on('dispose', () => { @@ -493,10 +610,10 @@ class Tech extends Component { } /** - * Get videotracks + * Get the `Tech`s {@link VideoTrackList}. * - * @returns {VideoTrackList} - * @method videoTracks + * @return {VideoTrackList} + * The video track list that the Tech is currently using. */ videoTracks() { this.videoTracks_ = this.videoTracks_ || new VideoTrackList(); @@ -504,27 +621,21 @@ class Tech extends Component { } /** - * Get audiotracklist + * Get the `Tech`s {@link AudioTrackList}. * - * @returns {AudioTrackList} - * @method audioTracks + * @return {AudioTrackList} + * The audio track list that the Tech is currently using. */ audioTracks() { this.audioTracks_ = this.audioTracks_ || new AudioTrackList(); return this.audioTracks_; } - /* - * Provide default methods for text tracks. - * - * Html5 tech overrides these. - */ - /** - * Get texttracks + * Get the `Tech`s {@link TextTrackList}. * - * @returns {TextTrackList} - * @method textTracks + * @return {TextTrackList} + * The text track list that the Tech is currently using. */ textTracks() { this.textTracks_ = this.textTracks_ || new TextTrackList(); @@ -532,10 +643,11 @@ class Tech extends Component { } /** - * Get remote texttracks + * Get the `Tech`s remote {@link TextTrackList}, which is created from elements + * that were added to the DOM. * - * @returns {TextTrackList} - * @method remoteTextTracks + * @return {TextTrackList} + * The remote text track list that the Tech is currently using. */ remoteTextTracks() { this.remoteTextTracks_ = this.remoteTextTracks_ || new TextTrackList(); @@ -543,10 +655,11 @@ class Tech extends Component { } /** - * Get remote htmltrackelements + * Get The `Tech`s {HTMLTrackElementList}, which are the elements in the DOM that are + * being used as TextTracks. * - * @returns {HTMLTrackElementList} - * @method remoteTextTrackEls + * @return {HTMLTrackElementList} + * The current HTML track elements that exist for the tech. */ remoteTextTrackEls() { this.remoteTextTrackEls_ = this.remoteTextTrackEls_ || new HTMLTrackElementList(); @@ -554,14 +667,19 @@ class Tech extends Component { } /** - * Creates and returns a remote text track object + * Create and returns a remote {@link TextTrack} object. * - * @param {String} kind Text track kind (subtitles, captions, descriptions - * chapters and metadata) - * @param {String=} label Label to identify the text track - * @param {String=} language Two letter language abbreviation - * @return {TextTrackObject} - * @method addTextTrack + * @param {string} kind + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata) + * + * @param {string} [label] + * Label to identify the text track + * + * @param {string} [language] + * Two letter language abbreviation + * + * @return {TextTrack} + * The TextTrack that gets created. */ addTextTrack(kind, label, language) { if (!kind) { @@ -577,8 +695,20 @@ class Tech extends Component { * This is intended to be overridden by classes that inherit from * Tech in order to create native or custom TextTracks. * - * @param {Object} options The object should contain values for - * kind, language, label and src (location of the WebVTT file) + * @param {Object} options + * The object should contain the options to initialize the TextTrack with. + * + * @param {string} [options.kind] + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata). + * + * @param {string} [options.label]. + * Label to identify the text track + * + * @param {string} [options.language] + * Two letter language abbreviation. + * + * @return {HTMLTrackElement} + * The track element that gets created. */ createRemoteTextTrack(options) { const track = mergeOptions(options, { @@ -591,14 +721,22 @@ class Tech extends Component { /** * Creates a remote text track object and returns an html track element. * - * @param {Object} options The object should contain values for - * kind, language, label, and src (location of the WebVTT file) - * @param {Boolean} [manualCleanup=true] if set to false, the TextTrack will be - * automatically removed from the video element whenever the source changes - * @return {HTMLTrackElement} An Html Track Element. - * This can be an emulated {@link HTMLTrackElement} or a native one. - * @deprecated The default value of the "manualCleanup" parameter will default - * to "false" in upcoming versions of Video.js + * > Note: This can be an emulated {@link HTMLTrackElement} or a native one. + * + * @param {Object} options + * See {@link Tech#createRemoteTextTrack} for more detailed properties. + * + * @param {boolean} [manualCleanup=true] + * - When false: the TextTrack will be automatically removed from the video + * element whenever the source changes + * - When True: The TextTrack will have to be cleaned up manually + * + * @return {HTMLTrackElement} + * An Html Track Element. + * + * @deprecated The default functionality for this function will be equivalent + * to "manualCleanup=false" in the future. The manualCleanup parameter will + * also be removed. */ addRemoteTextTrack(options = {}, manualCleanup) { const htmlTrackElement = this.createRemoteTextTrack(options); @@ -622,10 +760,10 @@ class Tech extends Component { } /** - * Remove remote texttrack + * Remove a remote text track from the remote `TextTrackList`. * - * @param {TextTrackObject} track Texttrack to remove - * @method removeRemoteTextTrack + * @param {TextTrack} track + * `TextTrack` to remove from the `TextTrackList` */ removeRemoteTextTrack(track) { const trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track); @@ -637,22 +775,27 @@ class Tech extends Component { } /** - * Provide a default setPoster method for techs - * Poster support for techs should be optional, so we don't want techs to - * break if they don't have a way to set a poster. + * A method to set a poster from a `Tech`. * - * @method setPoster + * @abstract */ setPoster() {} /* - * Check if the tech can support the given type + * Check if the tech can support the given mime-type. * * The base tech does not support any type, but source handlers might * overwrite this. * - * @param {String} type The mimetype to check - * @return {String} 'probably', 'maybe', or '' (empty string) + * @param {string} type + * The mimetype to check for support + * + * @return {string} + * 'probably', 'maybe', or empty string + * + * @see [Spec]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType} + * + * @abstract */ canPlayType() { return ''; @@ -662,8 +805,13 @@ class Tech extends Component { * Return whether the argument is a Tech or not. * Can be passed either a Class like `Html5` or a instance like `player.tech_` * - * @param {Object} component An item to check - * @return {Boolean} Whether it is a tech or not + * @param {Object} component + * The item to check + * + * @return {boolean} + * Whether it is a tech or not + * - True if it is a tech + * - False if it is not */ static isTech(component) { return component.prototype instanceof Tech || @@ -672,12 +820,13 @@ class Tech extends Component { } /** - * Registers a Tech + * Registers a `Tech` into a shared list for videojs. * - * @param {String} name Name of the Tech to register - * @param {Object} tech The tech to register - * @static - * @method registerComponent + * @param {string} name + * Name of the `Tech` to register. + * + * @param {Object} tech + * The `Tech` class to register. */ static registerTech(name, tech) { if (!Tech.techs_) { @@ -693,12 +842,13 @@ class Tech extends Component { } /** - * Gets a component by name + * Get a `Tech` from the shared list by name. + * + * @param {string} name + * Name of the component to get * - * @param {String} name Name of the component to get - * @return {Component} - * @static - * @method getComponent + * @return {Tech|undefined} + * The `Tech` or undefined if there was no tech with the name requsted. */ static getTech(name) { if (Tech.techs_ && Tech.techs_[name]) { @@ -713,7 +863,7 @@ class Tech extends Component { } /** - * List of associated text tracks + * List of associated text tracks. * * @type {TextTrackList} * @private @@ -721,7 +871,7 @@ class Tech extends Component { Tech.prototype.textTracks_; // eslint-disable-line /** - * List of associated audio tracks + * List of associated audio tracks. * * @type {AudioTrackList} * @private @@ -729,43 +879,95 @@ Tech.prototype.textTracks_; // eslint-disable-line Tech.prototype.audioTracks_; // eslint-disable-line /** - * List of associated video tracks + * List of associated video tracks. * * @type {VideoTrackList} * @private */ Tech.prototype.videoTracks_; // eslint-disable-line +/** + * Boolean indicating wether the `Tech` supports volume control. + * + * @type {boolean} + * @default + */ Tech.prototype.featuresVolumeControl = true; -// Resizing plugins using request fullscreen reloads the plugin +/** + * Boolean indicating wether the `Tech` support fullscreen resize control. + * Resizing plugins using request fullscreen reloads the plugin + * + * @type {boolean} + * @default + */ Tech.prototype.featuresFullscreenResize = false; + +/** + * Boolean indicating wether the `Tech` supports changing the speed at which the video + * plays. Examples: + * - Set player to play 2x (twice) as fast + * - Set player to play 0.5x (half) as fast + * + * @type {boolean} + * @default + */ Tech.prototype.featuresPlaybackRate = false; -// Optional events that we can manually mimic with timers -// currently not triggered by video-js-swf +/** + * Boolean indicating wether the `Tech` supports the `progress` event. This is currently + * not triggered by video-js-swf. This will be used to determine if + * {@link Tech#manualProgressOn} should be called. + * + * @type {boolean} + * @default + */ Tech.prototype.featuresProgressEvents = false; + +/** + * Boolean indicating wether the `Tech` supports the `timeupdate` event. This is currently + * not triggered by video-js-swf. This will be used to determine if + * {@link Tech#manualTimeUpdates} should be called. + * + * @type {boolean} + * @default + */ Tech.prototype.featuresTimeupdateEvents = false; +/** + * Boolean indicating wether the `Tech` supports the native `TextTrack`s. + * This will help us integrate with native `TextTrack`s if the browser supports them. + * + * @type {boolean} + * @default + */ Tech.prototype.featuresNativeTextTracks = false; /** * A functional mixin for techs that want to use the Source Handler pattern. + * Source handlers are scripts for handling specific formats. + * The source handler pattern is used for adaptive formats (HLS, DASH) that + * manually load video data and feed it into a Source Buffer (Media Source Extensions) * - * ##### EXAMPLE: + * ```js + * Tech.withSourceHandlers.call(MyTech); + * ``` * - * Tech.withSourceHandlers(MyTech); + * @param {Tech} _Tech + * The tech to add source handler functions to. * + * @mixes Tech~SourceHandlerAdditions */ Tech.withSourceHandlers = function(_Tech) { /** * Register a source handler - * Source handlers are scripts for handling specific formats. - * The source handler pattern is used for adaptive formats (HLS, DASH) that - * manually load video data and feed it into a Source Buffer (Media Source Extensions) - * @param {Function} handler The source handler - * @param {Number} index The index to register the handler among existing handlers + * + * @param {Function} handler + * The source handler class + * + * @param {number} [index] + * Register it at the following index */ _Tech.registerSourceHandler = function(handler, index) { let handlers = _Tech.sourceHandlers; @@ -783,9 +985,14 @@ Tech.withSourceHandlers = function(_Tech) { }; /** - * Check if the tech can support the given type - * @param {String} type The mimetype to check - * @return {String} 'probably', 'maybe', or '' (empty string) + * Check if the tech can support the given type. Also checks the + * Techs sourceHandlers. + * + * @param {string} type + * The mimetype to check. + * + * @return {string} + * 'probably', 'maybe', or '' (empty string) */ _Tech.canPlayType = function(type) { const handlers = _Tech.sourceHandlers || []; @@ -803,12 +1010,19 @@ Tech.withSourceHandlers = function(_Tech) { }; /** - * Return the first source handler that supports the source + * Returns the first source handler that supports the source. + * * TODO: Answer question: should 'probably' be prioritized over 'maybe' - * @param {Object} source The source object - * @param {Object} options The options passed to the tech - * @returns {Object} The first source handler that supports the source - * @returns {null} Null if no source handler is found + * + * @param {Tech~SourceObject} source + * The source object + * + * @param {Object} options + * The options passed to the tech + * + * @return {SourceHandler|null} + * The first source handler that supports the source or null if + * no SourceHandler supports the source */ _Tech.selectSourceHandler = function(source, options) { const handlers = _Tech.sourceHandlers || []; @@ -826,10 +1040,16 @@ Tech.withSourceHandlers = function(_Tech) { }; /** - * Check if the tech can support the given source - * @param {Object} srcObj The source object - * @param {Object} options The options passed to the tech - * @return {String} 'probably', 'maybe', or '' (empty string) + * Check if the tech can support the given source. + * + * @param {Tech~SourceObject} srcObj + * The source object + * + * @param {Object} options + * The options passed to the tech + * + * @return {string} + * 'probably', 'maybe', or '' (empty string) */ _Tech.canPlaySource = function(srcObj, options) { const sh = _Tech.selectSourceHandler(srcObj, options); @@ -850,6 +1070,20 @@ Tech.withSourceHandlers = function(_Tech) { 'duration' ]; + /** + * A wrapper around {@link Tech#seekable} that will call a `SourceHandler`s seekable + * function if it exists, with a fallback to the Techs seekable function. + * + * @method _Tech.seekable + */ + + /** + * A wrapper around {@link Tech#duration} that will call a `SourceHandler`s duration + * function if it exists, otherwise it will fallback to the techs duration function. + * + * @method _Tech.duration + */ + deferrable.forEach(function(fnName) { const originalFn = this[fnName]; @@ -869,8 +1103,12 @@ Tech.withSourceHandlers = function(_Tech) { * Create a function for setting the source using a source object * and source handlers. * Should never be called unless a source handler was found. - * @param {Object} source A source object with src and type keys - * @return {Tech} self + * + * @param {Tech~SourceObject} source + * A source object with src and type keys + * + * @return {Tech} + * Returns itself; this method is chainable */ _Tech.prototype.setSource = function(source) { let sh = _Tech.selectSourceHandler(source, this.options_); @@ -905,19 +1143,30 @@ Tech.withSourceHandlers = function(_Tech) { return this; }; - // On the first loadstart after setSource + /** + * Called once for the first loadstart of a video. + * + * @listens Tech#loadstart + */ _Tech.prototype.firstLoadStartListener_ = function() { this.one(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_); }; // On successive loadstarts when setSource has not been called again + /** + * Called after the first loadstart for a video occurs. + * + * @listens Tech#loadstart + */ _Tech.prototype.successiveLoadStartListener_ = function() { this.disposeSourceHandler(); this.one(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_); }; - /* - * Clean up any existing source handler + /** + * Clean up any existing SourceHandlers and listeners when the Tech is disposed. + * + * @listens Tech#dispose */ _Tech.prototype.disposeSourceHandler = function() { // if we have a source and get another one @@ -947,6 +1196,7 @@ Tech.withSourceHandlers = function(_Tech) { Component.registerComponent('Tech', Tech); // Old name for Tech +// @deprecated Component.registerComponent('MediaTechController', Tech); Tech.registerTech('Tech', Tech); export default Tech;