| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2015-07-21 16:56:23 -04:00
										 |  |  |  * @file html5.js | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |  */ | 
					
						
							|  |  |  | import Tech from './tech.js'; | 
					
						
							| 
									
										
										
										
											2015-05-03 16:12:38 -07:00
										 |  |  | import * as Dom from '../utils/dom.js'; | 
					
						
							|  |  |  | import * as Url from '../utils/url.js'; | 
					
						
							|  |  |  | import log from '../utils/log.js'; | 
					
						
							|  |  |  | import * as browser from '../utils/browser.js'; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | import document from 'global/document'; | 
					
						
							| 
									
										
										
										
											2015-05-03 16:12:38 -07:00
										 |  |  | import window from 'global/window'; | 
					
						
							| 
									
										
										
										
											2022-05-23 16:23:13 -04:00
										 |  |  | import {defineLazyProperty, merge} from '../utils/obj'; | 
					
						
							|  |  |  | import {toTitleCase} from '../utils/str.js'; | 
					
						
							| 
									
										
										
										
											2020-03-12 11:26:09 -04:00
										 |  |  | import {NORMAL as TRACK_TYPES, REMOTE} from '../tracks/track-types'; | 
					
						
							| 
									
										
										
										
											2018-03-23 13:51:47 -04:00
										 |  |  | import setupSourceset from './setup-sourceset'; | 
					
						
							| 
									
										
										
										
											2020-03-26 17:26:26 -04:00
										 |  |  | import {silencePromise} from '../utils/promise'; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * HTML5 Media Controller - Wrapper for HTML5 Media API | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |  * @mixes Tech~SourceHandlerAdditions | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * @extends Tech | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |  */ | 
					
						
							|  |  |  | class Html5 extends Tech { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-28 14:58:15 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |   * Create an instance of this Tech. | 
					
						
							|  |  |  |   * | 
					
						
							|  |  |  |   * @param {Object} [options] | 
					
						
							|  |  |  |   *        The key/value store of player options. | 
					
						
							|  |  |  |   * | 
					
						
							| 
									
										
										
										
											2023-03-02 06:41:57 +01:00
										 |  |  |   * @param {Function} [ready] | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |   *        Callback function to call when the `HTML5` Tech is ready. | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |   constructor(options, ready) { | 
					
						
							| 
									
										
										
										
											2015-05-06 14:01:52 -04:00
										 |  |  |     super(options, ready); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-06 14:01:52 -04:00
										 |  |  |     const source = options.source; | 
					
						
							| 
									
										
										
										
											2016-04-20 15:46:49 -04:00
										 |  |  |     let crossoriginTracks = false; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-28 16:01:00 -04:00
										 |  |  |     this.featuresVideoFrameCallback = this.featuresVideoFrameCallback && this.el_.tagName === 'VIDEO'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     // Set the source if one is provided
 | 
					
						
							|  |  |  |     // 1) Check if the source is new (if not, we want to keep the original so playback isn't interrupted)
 | 
					
						
							|  |  |  |     // 2) Check to see if the network state of the tag was failed at init, and if so, reset the source
 | 
					
						
							|  |  |  |     // anyway so the error gets fired.
 | 
					
						
							| 
									
										
										
										
											2015-05-06 14:01:52 -04:00
										 |  |  |     if (source && (this.el_.currentSrc !== source.src || (options.tag && options.tag.initNetworkState_ === 3))) { | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |       this.setSource(source); | 
					
						
							| 
									
										
										
										
											2015-09-14 16:37:39 -07:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       this.handleLateInit_(this.el_); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 15:51:47 -04:00
										 |  |  |     // setup sourceset after late sourceset/init
 | 
					
						
							|  |  |  |     if (options.enableSourceset) { | 
					
						
							|  |  |  |       this.setupSourcesetHandling_(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-10 18:10:04 -05:00
										 |  |  |     this.isScrubbing_ = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     if (this.el_.hasChildNodes()) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-03 15:29:12 -04:00
										 |  |  |       const nodes = this.el_.childNodes; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |       let nodesLength = nodes.length; | 
					
						
							| 
									
										
										
										
											2016-08-03 15:29:12 -04:00
										 |  |  |       const removeNodes = []; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       while (nodesLength--) { | 
					
						
							| 
									
										
										
										
											2016-08-03 15:29:12 -04:00
										 |  |  |         const node = nodes[nodesLength]; | 
					
						
							|  |  |  |         const nodeName = node.nodeName.toLowerCase(); | 
					
						
							| 
									
										
										
										
											2015-12-08 11:24:51 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |         if (nodeName === 'track') { | 
					
						
							| 
									
										
										
										
											2015-05-06 14:01:52 -04:00
										 |  |  |           if (!this.featuresNativeTextTracks) { | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |             // Empty video tag tracks so the built-in player doesn't use them also.
 | 
					
						
							|  |  |  |             // This may not be fast enough to stop HTML5 browsers from reading the tags
 | 
					
						
							|  |  |  |             // so we'll need to turn off any default tracks if we're manually doing
 | 
					
						
							|  |  |  |             // captions and subtitles. videoElement.textTracks
 | 
					
						
							|  |  |  |             removeNodes.push(node); | 
					
						
							|  |  |  |           } else { | 
					
						
							| 
									
										
										
										
											2015-12-08 11:24:51 -05:00
										 |  |  |             // store HTMLTrackElement and TextTrack to remote list
 | 
					
						
							|  |  |  |             this.remoteTextTrackEls().addTrackElement_(node); | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  |             this.remoteTextTracks().addTrack(node.track); | 
					
						
							| 
									
										
										
										
											2017-03-07 13:53:57 -05:00
										 |  |  |             this.textTracks().addTrack(node.track); | 
					
						
							| 
									
										
										
										
											2016-04-20 15:46:49 -04:00
										 |  |  |             if (!crossoriginTracks && | 
					
						
							|  |  |  |                 !this.el_.hasAttribute('crossorigin') && | 
					
						
							|  |  |  |                 Url.isCrossOrigin(node.src)) { | 
					
						
							|  |  |  |               crossoriginTracks = true; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |       for (let i = 0; i < removeNodes.length; i++) { | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |         this.el_.removeChild(removeNodes[i]); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  |     this.proxyNativeTracks_(); | 
					
						
							|  |  |  |     if (this.featuresNativeTextTracks && crossoriginTracks) { | 
					
						
							| 
									
										
										
										
											2019-08-19 14:56:16 -04:00
										 |  |  |       log.warn('Text Tracks are being loaded from another origin but the crossorigin attribute isn\'t used.\n' + | 
					
						
							|  |  |  |             'This may prevent text tracks from loading.'); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-14 16:36:36 -04:00
										 |  |  |     // prevent iOS Safari from disabling metadata text tracks during native playback
 | 
					
						
							|  |  |  |     this.restoreMetadataTracksInIOSNativePlayer_(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     // Determine if native controls should be used
 | 
					
						
							|  |  |  |     // Our goal should be to get the custom controls on mobile solid everywhere
 | 
					
						
							|  |  |  |     // so we can remove this all together. Right now this will block custom
 | 
					
						
							|  |  |  |     // controls on touch enabled laptops like the Chrome Pixel
 | 
					
						
							| 
									
										
										
										
											2022-11-22 23:16:32 +01:00
										 |  |  |     if ((browser.TOUCH_ENABLED || browser.IS_IPHONE) && options.nativeControlsForTouch === true) { | 
					
						
							| 
									
										
										
										
											2015-08-21 17:43:07 -04:00
										 |  |  |       this.setControls(true); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:35:31 -04:00
										 |  |  |     // on iOS, we want to proxy `webkitbeginfullscreen` and `webkitendfullscreen`
 | 
					
						
							|  |  |  |     // into a `fullscreenchange` event
 | 
					
						
							|  |  |  |     this.proxyWebkitFullscreen_(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     this.triggerReady(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Dispose of `HTML5` media element and remove all tracks. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   dispose() { | 
					
						
							| 
									
										
										
										
											2018-05-16 11:19:45 -04:00
										 |  |  |     if (this.el_ && this.el_.resetSourceset_) { | 
					
						
							| 
									
										
										
										
											2018-05-09 15:51:47 -04:00
										 |  |  |       this.el_.resetSourceset_(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  |     Html5.disposeMediaElement(this.el_); | 
					
						
							| 
									
										
										
										
											2017-11-16 11:19:47 -05:00
										 |  |  |     this.options_ = null; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  |     // tech will handle clearing of the emulated track list
 | 
					
						
							|  |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-07 14:28:37 -05:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Modify the media element so that we can detect when | 
					
						
							|  |  |  |    * the source is changed. Fires `sourceset` just after the source has changed | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   setupSourcesetHandling_() { | 
					
						
							| 
									
										
										
										
											2018-03-23 13:51:47 -04:00
										 |  |  |     setupSourceset(this); | 
					
						
							| 
									
										
										
										
											2018-03-07 14:28:37 -05:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-14 16:36:36 -04:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * When a captions track is enabled in the iOS Safari native player, all other | 
					
						
							|  |  |  |    * tracks are disabled (including metadata tracks), which nulls all of their | 
					
						
							|  |  |  |    * associated cue points. This will restore metadata tracks to their pre-fullscreen | 
					
						
							|  |  |  |    * state in those cases so that cue points are not needlessly lost. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @private | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   restoreMetadataTracksInIOSNativePlayer_() { | 
					
						
							|  |  |  |     const textTracks = this.textTracks(); | 
					
						
							|  |  |  |     let metadataTracksPreFullscreenState; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // captures a snapshot of every metadata track's current state
 | 
					
						
							|  |  |  |     const takeMetadataTrackSnapshot = () => { | 
					
						
							|  |  |  |       metadataTracksPreFullscreenState = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       for (let i = 0; i < textTracks.length; i++) { | 
					
						
							|  |  |  |         const track = textTracks[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (track.kind === 'metadata') { | 
					
						
							|  |  |  |           metadataTracksPreFullscreenState.push({ | 
					
						
							|  |  |  |             track, | 
					
						
							|  |  |  |             storedMode: track.mode | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // snapshot each metadata track's initial state, and update the snapshot
 | 
					
						
							|  |  |  |     // each time there is a track 'change' event
 | 
					
						
							|  |  |  |     takeMetadataTrackSnapshot(); | 
					
						
							|  |  |  |     textTracks.addEventListener('change', takeMetadataTrackSnapshot); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-16 11:19:47 -05:00
										 |  |  |     this.on('dispose', () => textTracks.removeEventListener('change', takeMetadataTrackSnapshot)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-14 16:36:36 -04:00
										 |  |  |     const restoreTrackMode = () => { | 
					
						
							|  |  |  |       for (let i = 0; i < metadataTracksPreFullscreenState.length; i++) { | 
					
						
							|  |  |  |         const storedTrack = metadataTracksPreFullscreenState[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (storedTrack.track.mode === 'disabled' && storedTrack.track.mode !== storedTrack.storedMode) { | 
					
						
							|  |  |  |           storedTrack.track.mode = storedTrack.storedMode; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       // we only want this handler to be executed on the first 'change' event
 | 
					
						
							|  |  |  |       textTracks.removeEventListener('change', restoreTrackMode); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // when we enter fullscreen playback, stop updating the snapshot and
 | 
					
						
							|  |  |  |     // restore all track modes to their pre-fullscreen state
 | 
					
						
							|  |  |  |     this.on('webkitbeginfullscreen', () => { | 
					
						
							|  |  |  |       textTracks.removeEventListener('change', takeMetadataTrackSnapshot); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // remove the listener before adding it just in case it wasn't previously removed
 | 
					
						
							|  |  |  |       textTracks.removeEventListener('change', restoreTrackMode); | 
					
						
							|  |  |  |       textTracks.addEventListener('change', restoreTrackMode); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // start updating the snapshot again after leaving fullscreen
 | 
					
						
							|  |  |  |     this.on('webkitendfullscreen', () => { | 
					
						
							|  |  |  |       // remove the listener before adding it just in case it wasn't previously removed
 | 
					
						
							|  |  |  |       textTracks.removeEventListener('change', takeMetadataTrackSnapshot); | 
					
						
							|  |  |  |       textTracks.addEventListener('change', takeMetadataTrackSnapshot); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // remove the restoreTrackMode handler in case it wasn't triggered during fullscreen playback
 | 
					
						
							|  |  |  |       textTracks.removeEventListener('change', restoreTrackMode); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 13:16:01 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |    * Attempt to force override of tracks for the given type | 
					
						
							| 
									
										
										
										
											2018-04-19 13:16:01 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2018-09-28 14:58:15 -04:00
										 |  |  |    * @param {string} type - Track type to override, possible values include 'Audio', | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |    * 'Video', and 'Text'. | 
					
						
							| 
									
										
										
										
											2018-09-28 14:58:15 -04:00
										 |  |  |    * @param {boolean} override - If set to true native audio/video will be overridden, | 
					
						
							| 
									
										
										
										
											2018-04-19 13:16:01 -04:00
										 |  |  |    * otherwise native audio/video will potentially be used. | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |    * @private | 
					
						
							| 
									
										
										
										
											2018-04-19 13:16:01 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |   overrideNative_(type, override) { | 
					
						
							| 
									
										
										
										
											2018-04-19 13:16:01 -04:00
										 |  |  |     // If there is no behavioral change don't add/remove listeners
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |     if (override !== this[`featuresNative${type}Tracks`]) { | 
					
						
							| 
									
										
										
										
											2018-04-19 13:16:01 -04:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |     const lowerCaseType = type.toLowerCase(); | 
					
						
							| 
									
										
										
										
											2018-04-19 13:16:01 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |     if (this[`${lowerCaseType}TracksListeners_`]) { | 
					
						
							|  |  |  |       Object.keys(this[`${lowerCaseType}TracksListeners_`]).forEach((eventName) => { | 
					
						
							|  |  |  |         const elTracks = this.el()[`${lowerCaseType}Tracks`]; | 
					
						
							| 
									
										
										
										
											2018-04-19 13:16:01 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |         elTracks.removeEventListener(eventName, this[`${lowerCaseType}TracksListeners_`][eventName]); | 
					
						
							| 
									
										
										
										
											2018-04-19 13:16:01 -04:00
										 |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |     this[`featuresNative${type}Tracks`] = !override; | 
					
						
							|  |  |  |     this[`${lowerCaseType}TracksListeners_`] = null; | 
					
						
							| 
									
										
										
										
											2018-04-19 13:16:01 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |     this.proxyNativeTracksForType_(lowerCaseType); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-04-19 13:16:01 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Attempt to force override of native audio tracks. | 
					
						
							|  |  |  |    * | 
					
						
							| 
									
										
										
										
											2018-09-28 14:58:15 -04:00
										 |  |  |    * @param {boolean} override - If set to true native audio will be overridden, | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |    * otherwise native audio will potentially be used. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   overrideNativeAudioTracks(override) { | 
					
						
							|  |  |  |     this.overrideNative_('Audio', override); | 
					
						
							| 
									
										
										
										
											2018-04-19 13:16:01 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |    * Attempt to force override of native video tracks. | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2018-09-28 14:58:15 -04:00
										 |  |  |    * @param {boolean} override - If set to true native video will be overridden, | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |    * otherwise native video will potentially be used. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   overrideNativeVideoTracks(override) { | 
					
						
							|  |  |  |     this.overrideNative_('Video', override); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-28 14:58:15 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |    * Proxy native track list events for the given type to our track | 
					
						
							|  |  |  |    * lists if the browser we are playing in supports that type of track list. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @param {string} name - Track type; values include 'audio', 'video', and 'text' | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  |    * @private | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |   proxyNativeTracksForType_(name) { | 
					
						
							|  |  |  |     const props = TRACK_TYPES[name]; | 
					
						
							|  |  |  |     const elTracks = this.el()[props.getterName]; | 
					
						
							|  |  |  |     const techTracks = this[props.getterName](); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!this[`featuresNative${props.capitalName}Tracks`] || | 
					
						
							|  |  |  |         !elTracks || | 
					
						
							|  |  |  |         !elTracks.addEventListener) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const listeners = { | 
					
						
							| 
									
										
										
										
											2020-03-12 11:26:09 -04:00
										 |  |  |       change: (e) => { | 
					
						
							|  |  |  |         const event = { | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |           type: 'change', | 
					
						
							|  |  |  |           target: techTracks, | 
					
						
							|  |  |  |           currentTarget: techTracks, | 
					
						
							|  |  |  |           srcElement: techTracks | 
					
						
							| 
									
										
										
										
											2020-03-12 11:26:09 -04:00
										 |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         techTracks.trigger(event); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // if we are a text track change event, we should also notify the
 | 
					
						
							|  |  |  |         // remote text track list. This can potentially cause a false positive
 | 
					
						
							|  |  |  |         // if we were to get a change event on a non-remote track and
 | 
					
						
							|  |  |  |         // we triggered the event on the remote text track list which doesn't
 | 
					
						
							|  |  |  |         // contain that track. However, best practices mean looping through the
 | 
					
						
							|  |  |  |         // list of tracks and searching for the appropriate mode value, so,
 | 
					
						
							|  |  |  |         // this shouldn't pose an issue
 | 
					
						
							|  |  |  |         if (name === 'text') { | 
					
						
							|  |  |  |           this[REMOTE.remoteText.getterName]().trigger(event); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |       }, | 
					
						
							|  |  |  |       addtrack(e) { | 
					
						
							|  |  |  |         techTracks.addTrack(e.track); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       removetrack(e) { | 
					
						
							|  |  |  |         techTracks.removeTrack(e.track); | 
					
						
							| 
									
										
										
										
											2016-06-27 23:10:21 -04:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |     }; | 
					
						
							|  |  |  |     const removeOldTracks = function() { | 
					
						
							|  |  |  |       const removeTracks = []; | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |       for (let i = 0; i < techTracks.length; i++) { | 
					
						
							|  |  |  |         let found = false; | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |         for (let j = 0; j < elTracks.length; j++) { | 
					
						
							|  |  |  |           if (elTracks[j] === techTracks[i]) { | 
					
						
							|  |  |  |             found = true; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |         if (!found) { | 
					
						
							|  |  |  |           removeTracks.push(techTracks[i]); | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |       while (removeTracks.length) { | 
					
						
							|  |  |  |         techTracks.removeTrack(removeTracks.shift()); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2018-04-19 13:16:01 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |     this[props.getterName + 'Listeners_'] = listeners; | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |     Object.keys(listeners).forEach((eventName) => { | 
					
						
							|  |  |  |       const listener = listeners[eventName]; | 
					
						
							| 
									
										
										
										
											2017-01-19 15:16:28 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |       elTracks.addEventListener(eventName, listener); | 
					
						
							|  |  |  |       this.on('dispose', (e) => elTracks.removeEventListener(eventName, listener)); | 
					
						
							| 
									
										
										
										
											2016-04-22 14:31:12 -04:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2015-08-03 15:19:36 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-19 20:11:11 -04:00
										 |  |  |     // Remove (native) tracks that are not used anymore
 | 
					
						
							|  |  |  |     this.on('loadstart', removeOldTracks); | 
					
						
							|  |  |  |     this.on('dispose', (e) => this.off('loadstart', removeOldTracks)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Proxy all native track list events to our track lists if the browser we are playing | 
					
						
							|  |  |  |    * in supports that type of track list. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @private | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   proxyNativeTracks_() { | 
					
						
							|  |  |  |     TRACK_TYPES.names.forEach((name) => { | 
					
						
							|  |  |  |       this.proxyNativeTracksForType_(name); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Create the `Html5` Tech's DOM element. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    * | 
					
						
							|  |  |  |    * @return {Element} | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    *         The element that gets created. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   createEl() { | 
					
						
							| 
									
										
										
										
											2015-05-06 14:01:52 -04:00
										 |  |  |     let el = this.options_.tag; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Check if this browser supports moving the element into the box.
 | 
					
						
							|  |  |  |     // On the iPhone video will break if you move the element,
 | 
					
						
							|  |  |  |     // So we have to create a brand new element.
 | 
					
						
							| 
									
										
										
										
											2016-12-19 11:51:42 -05:00
										 |  |  |     // If we ingested the player div, we do not need to move the media element.
 | 
					
						
							|  |  |  |     if (!el || | 
					
						
							|  |  |  |         !(this.options_.playerElIngest || | 
					
						
							|  |  |  |           this.movingMediaElementInDOM)) { | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // If the original tag is still there, clone and remove it.
 | 
					
						
							|  |  |  |       if (el) { | 
					
						
							| 
									
										
										
										
											2015-08-19 19:35:53 -04:00
										 |  |  |         const clone = el.cloneNode(true); | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-19 11:51:42 -05:00
										 |  |  |         if (el.parentNode) { | 
					
						
							|  |  |  |           el.parentNode.insertBefore(clone, el); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |         Html5.disposeMediaElement(el); | 
					
						
							|  |  |  |         el = clone; | 
					
						
							| 
									
										
										
										
											2016-12-19 11:51:42 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2015-05-03 16:12:38 -07:00
										 |  |  |         el = document.createElement('video'); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // determine if native controls should be used
 | 
					
						
							| 
									
										
										
										
											2017-01-19 16:01:56 -05:00
										 |  |  |         const tagAttributes = this.options_.tag && Dom.getAttributes(this.options_.tag); | 
					
						
							| 
									
										
										
										
											2022-05-23 16:23:13 -04:00
										 |  |  |         const attributes = merge({}, tagAttributes); | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-03 16:12:38 -07:00
										 |  |  |         if (!browser.TOUCH_ENABLED || this.options_.nativeControlsForTouch !== true) { | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |           delete attributes.controls; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-28 14:58:15 -04:00
										 |  |  |         Dom.setAttributes( | 
					
						
							|  |  |  |           el, | 
					
						
							| 
									
										
										
										
											2022-05-23 16:23:13 -04:00
										 |  |  |           Object.assign(attributes, { | 
					
						
							| 
									
										
										
										
											2015-05-18 11:29:07 -04:00
										 |  |  |             id: this.options_.techId, | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |             class: 'vjs-tech' | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-09-28 13:59:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       el.playerId = this.options_.playerId; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 17:48:17 -04:00
										 |  |  |     if (typeof this.options_.preload !== 'undefined') { | 
					
						
							| 
									
										
										
										
											2017-08-15 17:02:07 -04:00
										 |  |  |       Dom.setAttribute(el, 'preload', this.options_.preload); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-22 18:41:21 +02:00
										 |  |  |     if (this.options_.disablePictureInPicture !== undefined) { | 
					
						
							|  |  |  |       el.disablePictureInPicture = this.options_.disablePictureInPicture; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     // Update specific tag settings, in case they were overridden
 | 
					
						
							| 
									
										
										
										
											2017-08-15 17:02:07 -04:00
										 |  |  |     // `autoplay` has to be *last* so that `muted` and `playsinline` are present
 | 
					
						
							|  |  |  |     // when iOS/Safari or other browsers attempt to autoplay.
 | 
					
						
							|  |  |  |     const settingsAttrs = ['loop', 'muted', 'playsinline', 'autoplay']; | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-13 14:49:02 -05:00
										 |  |  |     for (let i = 0; i < settingsAttrs.length; i++) { | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |       const attr = settingsAttrs[i]; | 
					
						
							| 
									
										
										
										
											2017-08-15 17:02:07 -04:00
										 |  |  |       const value = this.options_[attr]; | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 17:02:07 -04:00
										 |  |  |       if (typeof value !== 'undefined') { | 
					
						
							|  |  |  |         if (value) { | 
					
						
							|  |  |  |           Dom.setAttribute(el, attr, attr); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           Dom.removeAttribute(el, attr); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         el[attr] = value; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return el; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * 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. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-09-14 16:37:39 -07:00
										 |  |  |   handleLateInit_(el) { | 
					
						
							|  |  |  |     if (el.networkState === 0 || el.networkState === 3) { | 
					
						
							|  |  |  |       // The video element hasn't started loading the source yet
 | 
					
						
							|  |  |  |       // or didn't find a source
 | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (el.readyState === 0) { | 
					
						
							|  |  |  |       // NetworkState is set synchronously BUT loadstart is fired at the
 | 
					
						
							|  |  |  |       // end of the current stack, usually before setInterval(fn, 0).
 | 
					
						
							|  |  |  |       // So at this point we know loadstart may have already fired or is
 | 
					
						
							|  |  |  |       // about to fire, and either way the player hasn't seen it yet.
 | 
					
						
							|  |  |  |       // We don't want to fire loadstart prematurely here and cause a
 | 
					
						
							|  |  |  |       // double loadstart so we'll wait and see if it happens between now
 | 
					
						
							|  |  |  |       // and the next loop, and fire it if not.
 | 
					
						
							|  |  |  |       // HOWEVER, we also want to make sure it fires before loadedmetadata
 | 
					
						
							|  |  |  |       // which could also happen between now and the next loop, so we'll
 | 
					
						
							|  |  |  |       // watch for that also.
 | 
					
						
							|  |  |  |       let loadstartFired = false; | 
					
						
							| 
									
										
										
										
											2016-08-03 15:29:12 -04:00
										 |  |  |       const setLoadstartFired = function() { | 
					
						
							| 
									
										
										
										
											2015-09-14 16:37:39 -07:00
										 |  |  |         loadstartFired = true; | 
					
						
							|  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-14 16:37:39 -07:00
										 |  |  |       this.on('loadstart', setLoadstartFired); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-03 15:29:12 -04:00
										 |  |  |       const triggerLoadstart = function() { | 
					
						
							| 
									
										
										
										
											2015-09-14 16:37:39 -07:00
										 |  |  |         // We did miss the original loadstart. Make sure the player
 | 
					
						
							|  |  |  |         // sees loadstart before loadedmetadata
 | 
					
						
							|  |  |  |         if (!loadstartFired) { | 
					
						
							|  |  |  |           this.trigger('loadstart'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-14 16:37:39 -07:00
										 |  |  |       this.on('loadedmetadata', triggerLoadstart); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |       this.ready(function() { | 
					
						
							| 
									
										
										
										
											2015-09-14 16:37:39 -07:00
										 |  |  |         this.off('loadstart', setLoadstartFired); | 
					
						
							|  |  |  |         this.off('loadedmetadata', triggerLoadstart); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!loadstartFired) { | 
					
						
							|  |  |  |           // We did miss the original native loadstart. Fire it now.
 | 
					
						
							|  |  |  |           this.trigger('loadstart'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // From here on we know that loadstart already fired and we missed it.
 | 
					
						
							|  |  |  |     // The other readyState events aren't as much of a problem if we double
 | 
					
						
							|  |  |  |     // them, so not going to go to as much trouble as loadstart to prevent
 | 
					
						
							|  |  |  |     // that unless we find reason to.
 | 
					
						
							| 
									
										
										
										
											2016-08-03 15:29:12 -04:00
										 |  |  |     const eventsToTrigger = ['loadstart']; | 
					
						
							| 
									
										
										
										
											2015-09-14 16:37:39 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // loadedmetadata: newly equal to HAVE_METADATA (1) or greater
 | 
					
						
							|  |  |  |     eventsToTrigger.push('loadedmetadata'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // loadeddata: newly increased to HAVE_CURRENT_DATA (2) or greater
 | 
					
						
							|  |  |  |     if (el.readyState >= 2) { | 
					
						
							|  |  |  |       eventsToTrigger.push('loadeddata'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // canplay: newly increased to HAVE_FUTURE_DATA (3) or greater
 | 
					
						
							|  |  |  |     if (el.readyState >= 3) { | 
					
						
							|  |  |  |       eventsToTrigger.push('canplay'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // canplaythrough: newly equal to HAVE_ENOUGH_DATA (4)
 | 
					
						
							|  |  |  |     if (el.readyState >= 4) { | 
					
						
							|  |  |  |       eventsToTrigger.push('canplaythrough'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // We still need to give the player time to add event listeners
 | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |     this.ready(function() { | 
					
						
							|  |  |  |       eventsToTrigger.forEach(function(type) { | 
					
						
							| 
									
										
										
										
											2015-09-14 16:37:39 -07:00
										 |  |  |         this.trigger(type); | 
					
						
							|  |  |  |       }, this); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 15:15:32 -04:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Set whether we are scrubbing or not. | 
					
						
							|  |  |  |    * This is used to decide whether we should use `fastSeek` or not. | 
					
						
							|  |  |  |    * `fastSeek` is used to provide trick play on Safari browsers. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @param {boolean} isScrubbing | 
					
						
							|  |  |  |    *                  - true for we are currently scrubbing | 
					
						
							|  |  |  |    *                  - false for we are no longer scrubbing | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2020-04-22 12:40:26 -04:00
										 |  |  |   setScrubbing(isScrubbing) { | 
					
						
							|  |  |  |     this.isScrubbing_ = isScrubbing; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-10 18:10:04 -05:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Get whether we are scrubbing or not. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @return {boolean} isScrubbing | 
					
						
							|  |  |  |    *                  - true for we are currently scrubbing | 
					
						
							|  |  |  |    *                  - false for we are no longer scrubbing | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   scrubbing() { | 
					
						
							|  |  |  |     return this.isScrubbing_; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Set current time for the `HTML5` tech. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @param {number} seconds | 
					
						
							|  |  |  |    *        Set the current time of the media to this. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   setCurrentTime(seconds) { | 
					
						
							|  |  |  |     try { | 
					
						
							| 
									
										
										
										
											2020-07-13 12:00:17 -04:00
										 |  |  |       if (this.isScrubbing_ && this.el_.fastSeek && browser.IS_ANY_SAFARI) { | 
					
						
							| 
									
										
										
										
											2020-04-22 12:40:26 -04:00
										 |  |  |         this.el_.fastSeek(seconds); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         this.el_.currentTime = seconds; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2015-05-03 16:12:38 -07:00
										 |  |  |       log(e, 'Video is not ready. (Video.js)'); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |       // this.warning(VideoJS.warnings.videoNotReady);
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Get the current duration of the HTML5 media element. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @return {number} | 
					
						
							|  |  |  |    *         The duration of the media or 0 if there is no duration. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |   duration() { | 
					
						
							| 
									
										
										
										
											2016-11-03 19:39:09 +00:00
										 |  |  |     // Android Chrome will report duration as Infinity for VOD HLS until after
 | 
					
						
							|  |  |  |     // playback has started, which triggers the live display erroneously.
 | 
					
						
							|  |  |  |     // Return NaN if playback has not started and trigger a durationupdate once
 | 
					
						
							|  |  |  |     // the duration can be reliably known.
 | 
					
						
							| 
									
										
										
										
											2017-06-28 02:32:58 -04:00
										 |  |  |     if ( | 
					
						
							|  |  |  |       this.el_.duration === Infinity && | 
					
						
							|  |  |  |       browser.IS_ANDROID && | 
					
						
							|  |  |  |       browser.IS_CHROME && | 
					
						
							|  |  |  |       this.el_.currentTime === 0 | 
					
						
							|  |  |  |     ) { | 
					
						
							|  |  |  |       // Wait for the first `timeupdate` with currentTime > 0 - there may be
 | 
					
						
							|  |  |  |       // several with 0
 | 
					
						
							|  |  |  |       const checkProgress = () => { | 
					
						
							|  |  |  |         if (this.el_.currentTime > 0) { | 
					
						
							|  |  |  |           // Trigger durationchange for genuinely live video
 | 
					
						
							|  |  |  |           if (this.el_.duration === Infinity) { | 
					
						
							|  |  |  |             this.trigger('durationchange'); | 
					
						
							| 
									
										
										
										
											2016-11-03 19:39:09 +00:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-06-28 02:32:58 -04:00
										 |  |  |           this.off('timeupdate', checkProgress); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2016-11-03 19:39:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 02:32:58 -04:00
										 |  |  |       this.on('timeupdate', checkProgress); | 
					
						
							|  |  |  |       return NaN; | 
					
						
							| 
									
										
										
										
											2016-11-03 19:39:09 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     return this.el_.duration || NaN; | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Get the current width of the HTML5 media element. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @return {number} | 
					
						
							|  |  |  |    *         The width of the HTML5 media element. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |   width() { | 
					
						
							|  |  |  |     return this.el_.offsetWidth; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Get the current height of the HTML5 media element. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @return {number} | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |    *         The height of the HTML5 media element. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |   height() { | 
					
						
							|  |  |  |     return this.el_.offsetHeight; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:35:31 -04:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Proxy iOS `webkitbeginfullscreen` and `webkitendfullscreen` into | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * `fullscreenchange` event. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:35:31 -04:00
										 |  |  |    * | 
					
						
							|  |  |  |    * @private | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @fires fullscreenchange | 
					
						
							|  |  |  |    * @listens webkitendfullscreen | 
					
						
							|  |  |  |    * @listens webkitbeginfullscreen | 
					
						
							|  |  |  |    * @listens webkitbeginfullscreen | 
					
						
							| 
									
										
										
										
											2016-09-29 14:35:31 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   proxyWebkitFullscreen_() { | 
					
						
							|  |  |  |     if (!('webkitDisplayingFullscreen' in this.el_)) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const endFn = function() { | 
					
						
							|  |  |  |       this.trigger('fullscreenchange', { isFullscreen: false }); | 
					
						
							| 
									
										
										
										
											2023-03-22 23:00:01 +09:00
										 |  |  |       // Safari will sometimes set controls on the videoelement when existing fullscreen.
 | 
					
						
							| 
									
										
										
										
											2022-02-23 18:17:49 +01:00
										 |  |  |       if (this.el_.controls && !this.options_.nativeControlsForTouch && this.controls()) { | 
					
						
							|  |  |  |         this.el_.controls = false; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-09-29 14:35:31 -04:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const beginFn = function() { | 
					
						
							| 
									
										
										
										
											2022-02-23 18:17:49 +01:00
										 |  |  |       if ('webkitPresentationMode' in this.el_ && this.el_.webkitPresentationMode !== 'picture-in-picture') { | 
					
						
							| 
									
										
										
										
											2017-06-28 07:35:01 +01:00
										 |  |  |         this.one('webkitendfullscreen', endFn); | 
					
						
							| 
									
										
										
										
											2016-09-29 14:35:31 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-28 10:29:36 -04:00
										 |  |  |         this.trigger('fullscreenchange', { | 
					
						
							|  |  |  |           isFullscreen: true, | 
					
						
							|  |  |  |           // set a flag in case another tech triggers fullscreenchange
 | 
					
						
							|  |  |  |           nativeIOSFullscreen: true | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-06-28 07:35:01 +01:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-09-29 14:35:31 -04:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this.on('webkitbeginfullscreen', beginFn); | 
					
						
							|  |  |  |     this.on('dispose', () => { | 
					
						
							|  |  |  |       this.off('webkitbeginfullscreen', beginFn); | 
					
						
							|  |  |  |       this.off('webkitendfullscreen', endFn); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2023-01-24 11:45:49 +01:00
										 |  |  |    * Check if fullscreen is supported on the video el. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @return {boolean} | 
					
						
							|  |  |  |    *         - True if fullscreen is supported. | 
					
						
							|  |  |  |    *         - False if fullscreen is not supported. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   supportsFullScreen() { | 
					
						
							| 
									
										
										
										
											2023-01-24 11:45:49 +01:00
										 |  |  |     return typeof this.el_.webkitEnterFullScreen === 'function'; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Request that the `HTML5` Tech enter fullscreen. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   enterFullScreen() { | 
					
						
							| 
									
										
										
										
											2016-08-03 15:29:12 -04:00
										 |  |  |     const video = this.el_; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (video.paused && video.networkState <= video.HAVE_METADATA) { | 
					
						
							|  |  |  |       // attempt to prime the video element for programmatic access
 | 
					
						
							|  |  |  |       // this isn't necessary on the desktop but shouldn't hurt
 | 
					
						
							| 
									
										
										
										
											2020-03-26 17:26:26 -04:00
										 |  |  |       silencePromise(this.el_.play()); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // playing and pausing synchronously during the transition to fullscreen
 | 
					
						
							|  |  |  |       // can get iOS ~6.1 devices into a play/pause loop
 | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |       this.setTimeout(function() { | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |         video.pause(); | 
					
						
							| 
									
										
										
										
											2020-03-26 17:26:26 -04:00
										 |  |  |         try { | 
					
						
							|  |  |  |           video.webkitEnterFullScreen(); | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |           this.trigger('fullscreenerror', e); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |       }, 0); | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2020-03-26 17:26:26 -04:00
										 |  |  |       try { | 
					
						
							|  |  |  |         video.webkitEnterFullScreen(); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         this.trigger('fullscreenerror', e); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Request that the `HTML5` Tech exit fullscreen. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   exitFullScreen() { | 
					
						
							| 
									
										
										
										
											2020-03-26 17:26:26 -04:00
										 |  |  |     if (!this.el_.webkitDisplayingFullscreen) { | 
					
						
							|  |  |  |       this.trigger('fullscreenerror', new Error('The video is not fullscreen')); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     this.el_.webkitExitFullScreen(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-11 19:21:02 +02:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Create a floating video window always on top of other windows so that users may | 
					
						
							|  |  |  |    * continue consuming media while they interact with other content sites, or | 
					
						
							|  |  |  |    * applications on their device. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @see [Spec]{@link https://wicg.github.io/picture-in-picture}
 | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @return {Promise} | 
					
						
							|  |  |  |    *         A promise with a Picture-in-Picture window. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   requestPictureInPicture() { | 
					
						
							|  |  |  |     return this.el_.requestPictureInPicture(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 16:34:13 +01:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Native requestVideoFrameCallback if supported by browser/tech, or fallback | 
					
						
							| 
									
										
										
										
											2022-07-28 20:20:46 +02:00
										 |  |  |    * Don't use rVCF on Safari when DRM is playing, as it doesn't fire | 
					
						
							|  |  |  |    * Needs to be checked later than the constructor | 
					
						
							|  |  |  |    * This will be a false positive for clear sources loaded after a Fairplay source | 
					
						
							| 
									
										
										
										
											2022-03-02 16:34:13 +01:00
										 |  |  |    * | 
					
						
							|  |  |  |    * @param {function} cb function to call | 
					
						
							|  |  |  |    * @return {number} id of request | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   requestVideoFrameCallback(cb) { | 
					
						
							| 
									
										
										
										
											2022-07-28 20:20:46 +02:00
										 |  |  |     if (this.featuresVideoFrameCallback && !this.el_.webkitKeys) { | 
					
						
							| 
									
										
										
										
											2022-03-02 16:34:13 +01:00
										 |  |  |       return this.el_.requestVideoFrameCallback(cb); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return super.requestVideoFrameCallback(cb); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Native or fallback requestVideoFrameCallback | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @param {number} id request id to cancel | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   cancelVideoFrameCallback(id) { | 
					
						
							| 
									
										
										
										
											2022-07-28 20:20:46 +02:00
										 |  |  |     if (this.featuresVideoFrameCallback && !this.el_.webkitKeys) { | 
					
						
							| 
									
										
										
										
											2022-03-02 16:34:13 +01:00
										 |  |  |       this.el_.cancelVideoFrameCallback(id); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       super.cancelVideoFrameCallback(id); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * A getter/setter for the `Html5` Tech's source object. | 
					
						
							|  |  |  |    * > Note: Please use {@link Html5#setSource} | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   src(src) { | 
					
						
							|  |  |  |     if (src === undefined) { | 
					
						
							|  |  |  |       return this.el_.src; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Setting src through `src` instead of `setSrc` will be deprecated
 | 
					
						
							|  |  |  |     this.setSrc(src); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-09 12:16:04 -04:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Add a <source> element to the <video> element. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @param {string} srcUrl | 
					
						
							|  |  |  |    *        The URL of the video source. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @param {string} [mimeType] | 
					
						
							|  |  |  |    *        The MIME type of the video source. Optional but recommended. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @return {boolean} | 
					
						
							|  |  |  |    *         Returns true if the source element was successfully added, false otherwise. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   addSourceElement(srcUrl, mimeType) { | 
					
						
							|  |  |  |     if (!srcUrl) { | 
					
						
							|  |  |  |       log.error('Invalid source URL.'); | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const sourceAttributes = { src: srcUrl }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mimeType) { | 
					
						
							|  |  |  |       sourceAttributes.type = mimeType; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const sourceElement = Dom.createEl('source', {}, sourceAttributes); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this.el_.appendChild(sourceElement); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Remove a <source> element from the <video> element by its URL. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @param {string} srcUrl | 
					
						
							|  |  |  |    *        The URL of the source to remove. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @return {boolean} | 
					
						
							|  |  |  |    *         Returns true if the source element was successfully removed, false otherwise. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   removeSourceElement(srcUrl) { | 
					
						
							|  |  |  |     if (!srcUrl) { | 
					
						
							|  |  |  |       log.error('Source URL is required to remove the source element.'); | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const sourceElements = this.el_.querySelectorAll('source'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (const sourceElement of sourceElements) { | 
					
						
							|  |  |  |       if (sourceElement.src === srcUrl) { | 
					
						
							|  |  |  |         this.el_.removeChild(sourceElement); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     log.warn(`No matching source element found with src: ${srcUrl}`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-07 17:45:50 -05:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Reset the tech by removing all sources and then calling | 
					
						
							|  |  |  |    * {@link Html5.resetMediaElement}. | 
					
						
							| 
									
										
										
										
											2015-12-07 17:45:50 -05:00
										 |  |  |    */ | 
					
						
							|  |  |  |   reset() { | 
					
						
							|  |  |  |     Html5.resetMediaElement(this.el_); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Get the current source on the `HTML5` Tech. Falls back to returning the source from | 
					
						
							|  |  |  |    * the HTML5 media element. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @return {Tech~SourceObject} | 
					
						
							|  |  |  |    *         The current source object from the HTML5 tech. With a fallback to the | 
					
						
							|  |  |  |    *         elements source. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2016-03-29 17:19:59 -04:00
										 |  |  |   currentSrc() { | 
					
						
							| 
									
										
										
										
											2015-11-23 12:04:31 -05:00
										 |  |  |     if (this.currentSource_) { | 
					
						
							|  |  |  |       return this.currentSource_.src; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |     return this.el_.currentSrc; | 
					
						
							| 
									
										
										
										
											2015-11-23 12:04:31 -05:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Set controls attribute for the HTML5 media Element. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @param {string} val | 
					
						
							|  |  |  |    *        Value to set the controls attribute to | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |   setControls(val) { | 
					
						
							|  |  |  |     this.el_.controls = !!val; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * 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 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @param {string} [language] | 
					
						
							|  |  |  |    *        Two letter language abbreviation | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @return {TextTrack} | 
					
						
							|  |  |  |    *         The TextTrack that gets created. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   addTextTrack(kind, label, language) { | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |     if (!this.featuresNativeTextTracks) { | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |       return super.addTextTrack(kind, label, language); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return this.el_.addTextTrack(kind, label, language); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-11-09 16:07:59 -05:00
										 |  |  |    * Creates either native TextTrack or an emulated TextTrack depending | 
					
						
							|  |  |  |    * on the value of `featuresNativeTextTracks` | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @param {Object} options | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |    *        The object should contain the options to initialize the TextTrack with. | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * | 
					
						
							|  |  |  |    * @param {string} [options.kind] | 
					
						
							|  |  |  |    *        `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata). | 
					
						
							|  |  |  |    * | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |    * @param {string} [options.label] | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    *        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. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2016-11-09 16:07:59 -05:00
										 |  |  |   createRemoteTextTrack(options) { | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |     if (!this.featuresNativeTextTracks) { | 
					
						
							| 
									
										
										
										
											2016-11-09 16:07:59 -05:00
										 |  |  |       return super.createRemoteTextTrack(options); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-08-03 15:29:12 -04:00
										 |  |  |     const htmlTrackElement = document.createElement('track'); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-08 11:24:51 -05:00
										 |  |  |     if (options.kind) { | 
					
						
							|  |  |  |       htmlTrackElement.kind = options.kind; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-12-08 11:24:51 -05:00
										 |  |  |     if (options.label) { | 
					
						
							|  |  |  |       htmlTrackElement.label = options.label; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-12-08 11:24:51 -05:00
										 |  |  |     if (options.language || options.srclang) { | 
					
						
							|  |  |  |       htmlTrackElement.srclang = options.language || options.srclang; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-12-08 11:24:51 -05:00
										 |  |  |     if (options.default) { | 
					
						
							|  |  |  |       htmlTrackElement.default = options.default; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-12-08 11:24:51 -05:00
										 |  |  |     if (options.id) { | 
					
						
							|  |  |  |       htmlTrackElement.id = options.id; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-12-08 11:24:51 -05:00
										 |  |  |     if (options.src) { | 
					
						
							|  |  |  |       htmlTrackElement.src = options.src; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-09 16:07:59 -05:00
										 |  |  |     return htmlTrackElement; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * 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) | 
					
						
							| 
									
										
										
										
											2022-01-13 12:25:26 -05:00
										 |  |  |    * @param {boolean} [manualCleanup=false] if set to true, the TextTrack | 
					
						
							|  |  |  |    * will not be removed from the TextTrackList and HtmlTrackElementList | 
					
						
							|  |  |  |    * after a source change | 
					
						
							| 
									
										
										
										
											2016-11-09 16:07:59 -05:00
										 |  |  |    * @return {HTMLTrackElement} An Html Track Element. | 
					
						
							|  |  |  |    * This can be an emulated {@link HTMLTrackElement} or a native one. | 
					
						
							| 
									
										
										
										
											2022-01-13 12:25:26 -05:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-11-09 16:07:59 -05:00
										 |  |  |    */ | 
					
						
							|  |  |  |   addRemoteTextTrack(options, manualCleanup) { | 
					
						
							|  |  |  |     const htmlTrackElement = super.addRemoteTextTrack(options, manualCleanup); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-11 14:35:04 -05:00
										 |  |  |     if (this.featuresNativeTextTracks) { | 
					
						
							|  |  |  |       this.el().appendChild(htmlTrackElement); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-08 11:24:51 -05:00
										 |  |  |     return htmlTrackElement; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Remove remote `TextTrack` from `TextTrackList` object | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @param {TextTrack} track | 
					
						
							|  |  |  |    *        `TextTrack` object to remove | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   removeRemoteTextTrack(track) { | 
					
						
							| 
									
										
										
										
											2016-11-09 16:07:59 -05:00
										 |  |  |     super.removeRemoteTextTrack(track); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-11 14:35:04 -05:00
										 |  |  |     if (this.featuresNativeTextTracks) { | 
					
						
							|  |  |  |       const tracks = this.$$('track'); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-11 14:35:04 -05:00
										 |  |  |       let i = tracks.length; | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-11 14:35:04 -05:00
										 |  |  |       while (i--) { | 
					
						
							|  |  |  |         if (track === tracks[i] || track === tracks[i].track) { | 
					
						
							|  |  |  |           this.el().removeChild(tracks[i]); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-05-12 12:22:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Gets available media playback quality metrics as specified by the W3C's Media | 
					
						
							|  |  |  |    * Playback Quality API. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @see [Spec]{@link https://wicg.github.io/media-playback-quality}
 | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @return {Object} | 
					
						
							|  |  |  |    *         An object with supported media playback quality metrics | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   getVideoPlaybackQuality() { | 
					
						
							|  |  |  |     if (typeof this.el().getVideoPlaybackQuality === 'function') { | 
					
						
							|  |  |  |       return this.el().getVideoPlaybackQuality(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const videoPlaybackQuality = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (typeof this.el().webkitDroppedFrameCount !== 'undefined' && | 
					
						
							|  |  |  |         typeof this.el().webkitDecodedFrameCount !== 'undefined') { | 
					
						
							|  |  |  |       videoPlaybackQuality.droppedVideoFrames = this.el().webkitDroppedFrameCount; | 
					
						
							|  |  |  |       videoPlaybackQuality.totalVideoFrames = this.el().webkitDecodedFrameCount; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-02 12:05:57 -04:00
										 |  |  |     if (window.performance) { | 
					
						
							| 
									
										
										
										
											2017-05-12 12:22:02 -07:00
										 |  |  |       videoPlaybackQuality.creationTime = window.performance.now(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return videoPlaybackQuality; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* HTML5 Support Testing ---------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-29 16:44:06 -04:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Element for testing browser HTML5 media capabilities | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @type {Element} | 
					
						
							|  |  |  |  * @constant | 
					
						
							|  |  |  |  * @private | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | defineLazyProperty(Html5, 'TEST_VID', function() { | 
					
						
							|  |  |  |   if (!Dom.isReal()) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const video = document.createElement('video'); | 
					
						
							| 
									
										
										
										
											2016-12-23 11:30:49 -05:00
										 |  |  |   const track = document.createElement('track'); | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-23 11:30:49 -05:00
										 |  |  |   track.kind = 'captions'; | 
					
						
							|  |  |  |   track.srclang = 'en'; | 
					
						
							|  |  |  |   track.label = 'English'; | 
					
						
							| 
									
										
										
										
											2019-08-29 16:44:06 -04:00
										 |  |  |   video.appendChild(track); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return video; | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2015-05-03 16:12:38 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * Check if HTML5 media is supported by this browser/device. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * @return {boolean} | 
					
						
							|  |  |  |  *         - True if HTML5 media is supported. | 
					
						
							|  |  |  |  *         - False if HTML5 media is not supported. | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | Html5.isSupported = function() { | 
					
						
							| 
									
										
										
										
											2018-03-23 13:25:12 -04:00
										 |  |  |   // IE with no Media Player is a LIAR! (#984)
 | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   try { | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |     Html5.TEST_VID.volume = 0.5; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   } catch (e) { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-23 11:30:49 -05:00
										 |  |  |   return !!(Html5.TEST_VID && Html5.TEST_VID.canPlayType); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												feat: middleware (#3788)
Add middleware support. Middleware can function as go-between between the player and the tech. For example, it can modify the duration that the tech returns to the player. In addition, middleware allow for supporting custom video sources and types.
Currently, middleware can only intercept timeline methods like duration, currentTime, and setCurrentTime.
For example,
```js
videojs.use('video/foo', {
  setSource(src, next) {
    next(null, {
      src: 'http://example.com/video.mp4',
      type: 'video/mp4'
    });
  }
});
```
Will allow you to set a source with type `video/foo` which will play back `video.mp4`.
This makes setting the source asynchronous, which aligns it with the spec a bit more. Methods like play can still be called synchronously on the player after setting the source and the player will play once the source has loaded.
`sourceOrder` option was removed as well and it will now always use source ordering.
BREAKING CHANGE: setting the source is now asynchronous. `sourceOrder` option removed and made the default.
											
										 
											2017-01-19 17:29:09 -05:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Check if the tech can support the given type | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param {string} type | 
					
						
							|  |  |  |  *        The mimetype to check | 
					
						
							|  |  |  |  * @return {string} 'probably', 'maybe', or '' (empty string) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | Html5.canPlayType = function(type) { | 
					
						
							|  |  |  |   return Html5.TEST_VID.canPlayType(type); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Check if the tech can support the given source | 
					
						
							| 
									
										
										
										
											2018-09-28 14:58:15 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
											  
											
												feat: middleware (#3788)
Add middleware support. Middleware can function as go-between between the player and the tech. For example, it can modify the duration that the tech returns to the player. In addition, middleware allow for supporting custom video sources and types.
Currently, middleware can only intercept timeline methods like duration, currentTime, and setCurrentTime.
For example,
```js
videojs.use('video/foo', {
  setSource(src, next) {
    next(null, {
      src: 'http://example.com/video.mp4',
      type: 'video/mp4'
    });
  }
});
```
Will allow you to set a source with type `video/foo` which will play back `video.mp4`.
This makes setting the source asynchronous, which aligns it with the spec a bit more. Methods like play can still be called synchronously on the player after setting the source and the player will play once the source has loaded.
`sourceOrder` option was removed as well and it will now always use source ordering.
BREAKING CHANGE: setting the source is now asynchronous. `sourceOrder` option removed and made the default.
											
										 
											2017-01-19 17:29:09 -05:00
										 |  |  |  * @param {Object} srcObj | 
					
						
							|  |  |  |  *        The source object | 
					
						
							|  |  |  |  * @param {Object} options | 
					
						
							|  |  |  |  *        The options passed to the tech | 
					
						
							|  |  |  |  * @return {string} 'probably', 'maybe', or '' (empty string) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | Html5.canPlaySource = function(srcObj, options) { | 
					
						
							|  |  |  |   return Html5.canPlayType(srcObj.type); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |  * Check if the volume can be changed in this browser/device. | 
					
						
							|  |  |  |  * Volume cannot be changed in a lot of mobile devices. | 
					
						
							|  |  |  |  * Specifically, it can't be changed from 1 on iOS. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * @return {boolean} | 
					
						
							|  |  |  |  *         - True if volume can be controlled | 
					
						
							|  |  |  |  *         - False otherwise | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | Html5.canControlVolume = function() { | 
					
						
							| 
									
										
										
										
											2016-06-27 22:15:17 -04:00
										 |  |  |   // IE will error if Windows Media Player not installed #3315
 | 
					
						
							|  |  |  |   try { | 
					
						
							| 
									
										
										
										
											2016-08-03 15:29:12 -04:00
										 |  |  |     const volume = Html5.TEST_VID.volume; | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-27 22:15:17 -04:00
										 |  |  |     Html5.TEST_VID.volume = (volume / 2) + 0.1; | 
					
						
							| 
									
										
										
										
											2021-11-17 12:27:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const canControl = volume !== Html5.TEST_VID.volume; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // With the introduction of iOS 15, there are cases where the volume is read as
 | 
					
						
							|  |  |  |     // changed but reverts back to its original state at the start of the next tick.
 | 
					
						
							|  |  |  |     // To determine whether volume can be controlled on iOS,
 | 
					
						
							|  |  |  |     // a timeout is set and the volume is checked asynchronously.
 | 
					
						
							|  |  |  |     // Since `features` doesn't currently work asynchronously, the value is manually set.
 | 
					
						
							|  |  |  |     if (canControl && browser.IS_IOS) { | 
					
						
							|  |  |  |       window.setTimeout(() => { | 
					
						
							| 
									
										
										
										
											2021-12-01 17:33:11 -05:00
										 |  |  |         if (Html5 && Html5.prototype) { | 
					
						
							|  |  |  |           Html5.prototype.featuresVolumeControl = volume !== Html5.TEST_VID.volume; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-11-17 12:27:08 -05:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2021-12-01 17:33:11 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // default iOS to false, which will be updated in the timeout above.
 | 
					
						
							|  |  |  |       return false; | 
					
						
							| 
									
										
										
										
											2021-11-17 12:27:08 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return canControl; | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |   } catch (e) { | 
					
						
							| 
									
										
										
										
											2016-06-27 22:15:17 -04:00
										 |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-22 04:33:09 +10:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Check if the volume can be muted in this browser/device. | 
					
						
							|  |  |  |  * Some devices, e.g. iOS, don't allow changing volume | 
					
						
							|  |  |  |  * but permits muting/unmuting. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2023-03-02 06:41:57 +01:00
										 |  |  |  * @return {boolean} | 
					
						
							| 
									
										
										
										
											2018-06-22 04:33:09 +10:00
										 |  |  |  *      - True if volume can be muted | 
					
						
							|  |  |  |  *      - False otherwise | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | Html5.canMuteVolume = function() { | 
					
						
							|  |  |  |   try { | 
					
						
							|  |  |  |     const muted = Html5.TEST_VID.muted; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // in some versions of iOS muted property doesn't always
 | 
					
						
							|  |  |  |     // work, so we want to set both property and attribute
 | 
					
						
							|  |  |  |     Html5.TEST_VID.muted = !muted; | 
					
						
							|  |  |  |     if (Html5.TEST_VID.muted) { | 
					
						
							|  |  |  |       Dom.setAttribute(Html5.TEST_VID, 'muted', 'muted'); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       Dom.removeAttribute(Html5.TEST_VID, 'muted', 'muted'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return muted !== Html5.TEST_VID.muted; | 
					
						
							|  |  |  |   } catch (e) { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * Check if the playback rate can be changed in this browser/device. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * @return {boolean} | 
					
						
							|  |  |  |  *         - True if playback rate can be controlled | 
					
						
							|  |  |  |  *         - False otherwise | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | Html5.canControlPlaybackRate = function() { | 
					
						
							| 
									
										
										
										
											2016-04-19 15:13:50 -04:00
										 |  |  |   // Playback rate API is implemented in Android Chrome, but doesn't do anything
 | 
					
						
							|  |  |  |   // https://github.com/videojs/video.js/issues/3180
 | 
					
						
							| 
									
										
										
										
											2017-05-11 21:59:22 +01:00
										 |  |  |   if (browser.IS_ANDROID && browser.IS_CHROME && browser.CHROME_VERSION < 58) { | 
					
						
							| 
									
										
										
										
											2016-04-19 15:13:50 -04:00
										 |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-06-27 22:15:17 -04:00
										 |  |  |   // IE will error if Windows Media Player not installed #3315
 | 
					
						
							|  |  |  |   try { | 
					
						
							| 
									
										
										
										
											2016-08-03 15:29:12 -04:00
										 |  |  |     const playbackRate = Html5.TEST_VID.playbackRate; | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-27 22:15:17 -04:00
										 |  |  |     Html5.TEST_VID.playbackRate = (playbackRate / 2) + 0.1; | 
					
						
							|  |  |  |     return playbackRate !== Html5.TEST_VID.playbackRate; | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |   } catch (e) { | 
					
						
							| 
									
										
										
										
											2016-06-27 22:15:17 -04:00
										 |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-07 14:28:37 -05:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Check if we can override a video/audio elements attributes, with | 
					
						
							|  |  |  |  * Object.defineProperty. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @return {boolean} | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |  *         - True if builtin attributes can be overridden | 
					
						
							| 
									
										
										
										
											2018-03-07 14:28:37 -05:00
										 |  |  |  *         - False otherwise | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | Html5.canOverrideAttributes = function() { | 
					
						
							| 
									
										
										
										
											2018-04-02 16:06:26 -04:00
										 |  |  |   // if we cannot overwrite the src/innerHTML property, there is no support
 | 
					
						
							| 
									
										
										
										
											2018-03-07 14:28:37 -05:00
										 |  |  |   // iOS 7 safari for instance cannot do this.
 | 
					
						
							|  |  |  |   try { | 
					
						
							|  |  |  |     const noop = () => {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Object.defineProperty(document.createElement('video'), 'src', {get: noop, set: noop}); | 
					
						
							|  |  |  |     Object.defineProperty(document.createElement('audio'), 'src', {get: noop, set: noop}); | 
					
						
							| 
									
										
										
										
											2018-04-02 16:06:26 -04:00
										 |  |  |     Object.defineProperty(document.createElement('video'), 'innerHTML', {get: noop, set: noop}); | 
					
						
							|  |  |  |     Object.defineProperty(document.createElement('audio'), 'innerHTML', {get: noop, set: noop}); | 
					
						
							| 
									
										
										
										
											2018-03-07 14:28:37 -05:00
										 |  |  |   } catch (e) { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * Check to see if native `TextTrack`s are supported by this browser/device. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * @return {boolean} | 
					
						
							|  |  |  |  *         - True if native `TextTrack`s are supported. | 
					
						
							|  |  |  |  *         - False otherwise | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |  */ | 
					
						
							|  |  |  | Html5.supportsNativeTextTracks = function() { | 
					
						
							| 
									
										
										
										
											2018-06-27 04:36:33 +10:00
										 |  |  |   return browser.IS_ANY_SAFARI || (browser.IS_IOS && browser.IS_CHROME); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * Check to see if native `VideoTrack`s are supported by this browser/device | 
					
						
							| 
									
										
										
										
											2016-04-22 14:31:12 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * @return {boolean} | 
					
						
							|  |  |  |  *        - True if native `VideoTrack`s are supported. | 
					
						
							|  |  |  |  *        - False otherwise | 
					
						
							| 
									
										
										
										
											2016-04-22 14:31:12 -04:00
										 |  |  |  */ | 
					
						
							|  |  |  | Html5.supportsNativeVideoTracks = function() { | 
					
						
							| 
									
										
										
										
											2016-12-23 11:30:49 -05:00
										 |  |  |   return !!(Html5.TEST_VID && Html5.TEST_VID.videoTracks); | 
					
						
							| 
									
										
										
										
											2016-04-22 14:31:12 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * Check to see if native `AudioTrack`s are supported by this browser/device | 
					
						
							| 
									
										
										
										
											2016-04-22 14:31:12 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * @return {boolean} | 
					
						
							|  |  |  |  *        - True if native `AudioTrack`s are supported. | 
					
						
							|  |  |  |  *        - False otherwise | 
					
						
							| 
									
										
										
										
											2016-04-22 14:31:12 -04:00
										 |  |  |  */ | 
					
						
							|  |  |  | Html5.supportsNativeAudioTracks = function() { | 
					
						
							| 
									
										
										
										
											2016-12-23 11:30:49 -05:00
										 |  |  |   return !!(Html5.TEST_VID && Html5.TEST_VID.audioTracks); | 
					
						
							| 
									
										
										
										
											2016-04-22 14:31:12 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 15:36:25 -04:00
										 |  |  | /** | 
					
						
							|  |  |  |  * An array of events available on the Html5 tech. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @private | 
					
						
							|  |  |  |  * @type {Array} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | Html5.Events = [ | 
					
						
							|  |  |  |   'loadstart', | 
					
						
							|  |  |  |   'suspend', | 
					
						
							|  |  |  |   'abort', | 
					
						
							|  |  |  |   'error', | 
					
						
							|  |  |  |   'emptied', | 
					
						
							|  |  |  |   'stalled', | 
					
						
							|  |  |  |   'loadedmetadata', | 
					
						
							|  |  |  |   'loadeddata', | 
					
						
							|  |  |  |   'canplay', | 
					
						
							|  |  |  |   'canplaythrough', | 
					
						
							|  |  |  |   'playing', | 
					
						
							|  |  |  |   'waiting', | 
					
						
							|  |  |  |   'seeking', | 
					
						
							|  |  |  |   'seeked', | 
					
						
							|  |  |  |   'ended', | 
					
						
							|  |  |  |   'durationchange', | 
					
						
							|  |  |  |   'timeupdate', | 
					
						
							|  |  |  |   'progress', | 
					
						
							|  |  |  |   'play', | 
					
						
							|  |  |  |   'pause', | 
					
						
							|  |  |  |   'ratechange', | 
					
						
							| 
									
										
										
										
											2017-02-03 21:32:41 +00:00
										 |  |  |   'resize', | 
					
						
							| 
									
										
										
										
											2015-08-03 15:36:25 -04:00
										 |  |  |   'volumechange' | 
					
						
							|  |  |  | ]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * Boolean indicating whether the `Tech` supports volume control. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * @type {boolean} | 
					
						
							|  |  |  |  * @default {@link Html5.canControlVolume} | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-06-22 04:33:09 +10:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Boolean indicating whether the `Tech` supports muting volume. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2023-03-02 06:41:57 +01:00
										 |  |  |  * @type {boolean} | 
					
						
							| 
									
										
										
										
											2018-06-22 04:33:09 +10:00
										 |  |  |  * @default {@link Html5.canMuteVolume} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * 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 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * @type {boolean} | 
					
						
							|  |  |  |  * @default {@link Html5.canControlPlaybackRate} | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-07 14:28:37 -05:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |  * Boolean indicating whether the `Tech` supports the `sourceset` event. | 
					
						
							| 
									
										
										
										
											2018-03-07 14:28:37 -05:00
										 |  |  |  * | 
					
						
							|  |  |  |  * @type {boolean} | 
					
						
							|  |  |  |  * @default | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-08-29 16:44:06 -04:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Boolean indicating whether the `HTML5` tech currently supports native `TextTrack`s. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @type {boolean} | 
					
						
							|  |  |  |  * @default {@link Html5.supportsNativeTextTracks} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Boolean indicating whether the `HTML5` tech currently supports native `VideoTrack`s. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @type {boolean} | 
					
						
							|  |  |  |  * @default {@link Html5.supportsNativeVideoTracks} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Boolean indicating whether the `HTML5` tech currently supports native `AudioTrack`s. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @type {boolean} | 
					
						
							|  |  |  |  * @default {@link Html5.supportsNativeAudioTracks} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | [ | 
					
						
							|  |  |  |   ['featuresMuteControl', 'canMuteVolume'], | 
					
						
							|  |  |  |   ['featuresPlaybackRate', 'canControlPlaybackRate'], | 
					
						
							|  |  |  |   ['featuresSourceset', 'canOverrideAttributes'], | 
					
						
							|  |  |  |   ['featuresNativeTextTracks', 'supportsNativeTextTracks'], | 
					
						
							|  |  |  |   ['featuresNativeVideoTracks', 'supportsNativeVideoTracks'], | 
					
						
							|  |  |  |   ['featuresNativeAudioTracks', 'supportsNativeAudioTracks'] | 
					
						
							|  |  |  | ].forEach(function([key, fn]) { | 
					
						
							| 
									
										
										
										
											2019-12-02 14:13:36 -05:00
										 |  |  |   defineLazyProperty(Html5.prototype, key, () => Html5[fn](), true); | 
					
						
							| 
									
										
										
										
											2019-08-29 16:44:06 -04:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2018-03-07 14:28:37 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-01 17:33:11 -05:00
										 |  |  | Html5.prototype.featuresVolumeControl = Html5.canControlVolume(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * 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. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:31:18 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * @type {boolean} | 
					
						
							|  |  |  |  * @default | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | Html5.prototype.movingMediaElementInDOM = !browser.IS_IOS; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | // TODO: Previous comment: No longer appears to be used. Can probably be removed.
 | 
					
						
							|  |  |  | //       Is this true?
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * Boolean indicating whether the `HTML5` tech currently supports automatic media resize | 
					
						
							|  |  |  |  * when going into fullscreen. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @type {boolean} | 
					
						
							|  |  |  |  * @default | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | Html5.prototype.featuresFullscreenResize = true; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * Boolean indicating whether the `HTML5` tech currently supports the progress event. | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |  * If this is false, manual `progress` events will be triggered instead. | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * | 
					
						
							|  |  |  |  * @type {boolean} | 
					
						
							|  |  |  |  * @default | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | Html5.prototype.featuresProgressEvents = true; | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-30 22:57:16 +02:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * Boolean indicating whether the `HTML5` tech currently supports the timeupdate event. | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |  * If this is false, manual `timeupdate` events will be triggered instead. | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * | 
					
						
							|  |  |  |  * @default | 
					
						
							| 
									
										
										
										
											2016-09-30 22:57:16 +02:00
										 |  |  |  */ | 
					
						
							|  |  |  | Html5.prototype.featuresTimeupdateEvents = true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 16:34:13 +01:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Whether the HTML5 el supports `requestVideoFrameCallback` | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @type {boolean} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | Html5.prototype.featuresVideoFrameCallback = !!(Html5.TEST_VID && Html5.TEST_VID.requestVideoFrameCallback); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | Html5.disposeMediaElement = function(el) { | 
					
						
							|  |  |  |   if (!el) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (el.parentNode) { | 
					
						
							|  |  |  |     el.parentNode.removeChild(el); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // remove any child track or source nodes to prevent their loading
 | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |   while (el.hasChildNodes()) { | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |     el.removeChild(el.firstChild); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // remove any src reference. not setting `src=''` because that causes a warning
 | 
					
						
							|  |  |  |   // in firefox
 | 
					
						
							|  |  |  |   el.removeAttribute('src'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // force the media element to update its loading state by calling load()
 | 
					
						
							|  |  |  |   // however IE on Windows 7N has a bug that throws an error so need a try/catch (#793)
 | 
					
						
							|  |  |  |   if (typeof el.load === 'function') { | 
					
						
							|  |  |  |     // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473)
 | 
					
						
							|  |  |  |     (function() { | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         el.load(); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         // not supported
 | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |     }()); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | Html5.resetMediaElement = function(el) { | 
					
						
							|  |  |  |   if (!el) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-07 17:45:50 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-03 15:29:12 -04:00
										 |  |  |   const sources = el.querySelectorAll('source'); | 
					
						
							| 
									
										
										
										
											2015-12-07 17:45:50 -05:00
										 |  |  |   let i = sources.length; | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-07 17:45:50 -05:00
										 |  |  |   while (i--) { | 
					
						
							|  |  |  |     el.removeChild(sources[i]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // remove any src reference.
 | 
					
						
							|  |  |  |   // not setting `src=''` because that throws an error
 | 
					
						
							|  |  |  |   el.removeAttribute('src'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (typeof el.load === 'function') { | 
					
						
							|  |  |  |     // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473)
 | 
					
						
							|  |  |  |     (function() { | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         el.load(); | 
					
						
							| 
									
										
										
										
											2016-07-25 09:49:38 -04:00
										 |  |  |       } catch (e) { | 
					
						
							|  |  |  |         // satisfy linter
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }()); | 
					
						
							| 
									
										
										
										
											2015-12-07 17:45:50 -05:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | /* Native HTML5 element property wrapping ----------------------------------- */ | 
					
						
							| 
									
										
										
										
											2017-08-15 17:02:07 -04:00
										 |  |  | // Wrap native boolean attributes with getters that check both property and attribute
 | 
					
						
							|  |  |  | // The list is as followed:
 | 
					
						
							|  |  |  | // muted, defaultMuted, autoplay, controls, loop, playsinline
 | 
					
						
							|  |  |  | [ | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * 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. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#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 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. {@link Html5#muted} indicates the | 
					
						
							|  |  |  |    * current state. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#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 the value of `autoplay` from the media element. `autoplay` indicates | 
					
						
							|  |  |  |    * that the media should start to play as soon as the page is ready. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#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 the value of `controls` from the media element. `controls` indicates | 
					
						
							|  |  |  |    * whether the native media controls should be shown or hidden. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#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 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. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#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 the value of `playsinline` from the media element. `playsinline` indicates | 
					
						
							|  |  |  |    * to the browser that non-fullscreen playback is preferred when fullscreen | 
					
						
							|  |  |  |    * playback is the native default, such as in iOS Safari. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#playsinline | 
					
						
							|  |  |  |    * @return {boolean} | 
					
						
							|  |  |  |    *         - The value of `playsinline` from the media element. | 
					
						
							|  |  |  |    *         - True indicates that the media should play inline. | 
					
						
							|  |  |  |    *         - False indicates that the media should not play inline. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}
 | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   'playsinline' | 
					
						
							|  |  |  | ].forEach(function(prop) { | 
					
						
							|  |  |  |   Html5.prototype[prop] = function() { | 
					
						
							|  |  |  |     return this.el_[prop] || this.el_.hasAttribute(prop); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Wrap native boolean attributes with setters that set both property and attribute
 | 
					
						
							|  |  |  | // The list is as followed:
 | 
					
						
							|  |  |  | // setMuted, setDefaultMuted, setAutoplay, setLoop, setPlaysinline
 | 
					
						
							|  |  |  | // setControls is special-cased above
 | 
					
						
							|  |  |  | [ | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Set the value of `muted` on the media element. `muted` indicates that the current | 
					
						
							|  |  |  |    * audio level should be silent. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#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 the value of `defaultMuted` on the media element. `defaultMuted` indicates that the current | 
					
						
							| 
									
										
										
										
											2020-09-23 04:38:19 +10:00
										 |  |  |    * audio level should be silent, but will only effect the muted level on initial playback.. | 
					
						
							| 
									
										
										
										
											2017-08-15 17:02:07 -04:00
										 |  |  |    * | 
					
						
							|  |  |  |    * @method Html5.prototype.setDefaultMuted | 
					
						
							|  |  |  |    * @param {boolean} defaultMuted | 
					
						
							|  |  |  |    *        - 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-defaultmuted}
 | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   'defaultMuted', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * 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. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#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 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. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#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 the value of `playsinline` from the media element. `playsinline` indicates | 
					
						
							|  |  |  |    * to the browser that non-fullscreen playback is preferred when fullscreen | 
					
						
							|  |  |  |    * playback is the native default, such as in iOS Safari. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#setPlaysinline | 
					
						
							|  |  |  |    * @param {boolean} playsinline | 
					
						
							|  |  |  |    *         - True indicates that the media should play inline. | 
					
						
							|  |  |  |    *         - False indicates that the media should not play inline. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}
 | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   'playsinline' | 
					
						
							|  |  |  | ].forEach(function(prop) { | 
					
						
							|  |  |  |   Html5.prototype['set' + toTitleCase(prop)] = function(v) { | 
					
						
							|  |  |  |     this.el_[prop] = v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (v) { | 
					
						
							|  |  |  |       this.el_.setAttribute(prop, prop); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       this.el_.removeAttribute(prop); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | // Wrap native properties with a getter
 | 
					
						
							| 
									
										
										
										
											2017-08-15 17:02:07 -04:00
										 |  |  | // The list is as followed
 | 
					
						
							|  |  |  | // paused, currentTime, buffered, volume, poster, preload, error, seeking
 | 
					
						
							| 
									
										
										
										
											2020-04-22 18:41:21 +02:00
										 |  |  | // seekable, ended, playbackRate, defaultPlaybackRate, disablePictureInPicture
 | 
					
						
							|  |  |  | // played, networkState, readyState, videoWidth, videoHeight, crossOrigin
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | [ | 
					
						
							|  |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Get the value of `paused` from the media element. `paused` indicates whether the media element | 
					
						
							|  |  |  |    * is currently paused or not. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#paused | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'paused', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Get the value of `currentTime` from the media element. `currentTime` indicates | 
					
						
							|  |  |  |    * the current second that the media is at in playback. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#currentTime | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'currentTime', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * 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. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#buffered | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'buffered', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * 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). | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#volume | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'volume', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * 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. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#poster | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'poster', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * 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 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#preload | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'preload', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Get the value of the `error` from the media element. `error` indicates any | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |    * MediaError that may have occurred during playback. If error returns null there is no | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * current error. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#error | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'error', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Get the value of `seeking` from the media element. `seeking` indicates whether the | 
					
						
							|  |  |  |    * media is currently seeking to a new position or not. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#seeking | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @return {boolean} | 
					
						
							|  |  |  |    *         - The value of `seeking` from the media element. | 
					
						
							|  |  |  |    *         - True indicates that the media is currently seeking to a new position. | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |    *         - False indicates that the media is not seeking to a new position at this time. | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * | 
					
						
							|  |  |  |    * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seeking}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'seeking', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Get the value of `seekable` from the media element. `seekable` returns a | 
					
						
							|  |  |  |    * `TimeRange` object indicating ranges of time that can currently be `seeked` to. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#seekable | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'seekable', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Get the value of `ended` from the media element. `ended` indicates whether | 
					
						
							|  |  |  |    * the media has reached the end or not. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#ended | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'ended', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * 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. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#playbackRate | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'playbackRate', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-18 14:59:15 -05:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Get the value of `defaultPlaybackRate` from the media element. `defaultPlaybackRate` indicates | 
					
						
							|  |  |  |    * the rate at which the media is currently playing back. This value will not indicate the current | 
					
						
							|  |  |  |    * `playbackRate` after playback has started, use {@link Html5#playbackRate} for that. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * Examples: | 
					
						
							|  |  |  |    *   - if defaultPlaybackRate is set to 2, media will play twice as fast. | 
					
						
							|  |  |  |    *   - if defaultPlaybackRate is set to 0.5, media will play half as fast. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5.prototype.defaultPlaybackRate | 
					
						
							|  |  |  |    * @return {number} | 
					
						
							|  |  |  |    *         The value of `defaultPlaybackRate` 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}
 | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   'defaultPlaybackRate', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-22 18:41:21 +02:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Get the value of 'disablePictureInPicture' from the video element. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#disablePictureInPicture | 
					
						
							|  |  |  |    * @return {boolean} value | 
					
						
							|  |  |  |    *         - The value of `disablePictureInPicture` from the video element. | 
					
						
							|  |  |  |    *         - True indicates that the video can't be played in Picture-In-Picture mode | 
					
						
							|  |  |  |    *         - False indicates that the video can be played in Picture-In-Picture mode | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @see [Spec]{@link https://w3c.github.io/picture-in-picture/#disable-pip}
 | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   'disablePictureInPicture', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Get the value of `played` from the media element. `played` returns a `TimeRange` | 
					
						
							|  |  |  |    * object representing points in the media timeline that have been played. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#played | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'played', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * 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 | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |    * - 1: NETWORK_IDLE | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * - 2: NETWORK_LOADING | 
					
						
							|  |  |  |    * - 3: NETWORK_NO_SOURCE | 
					
						
							|  |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#networkState | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'networkState', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * 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 | 
					
						
							|  |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#readyState | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'readyState', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Get the value of `videoWidth` from the video element. `videoWidth` indicates | 
					
						
							|  |  |  |    * the current width of the video in css pixels. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#videoWidth | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'videoWidth', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |    * Get the value of `videoHeight` from the video element. `videoHeight` indicates | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * the current height of the video in css pixels. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#videoHeight | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2020-04-06 08:53:45 -07:00
										 |  |  |   'videoHeight', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Get the value of `crossOrigin` from the media element. `crossOrigin` indicates | 
					
						
							|  |  |  |    * to the browser that should sent the cookies along with the requests for the | 
					
						
							|  |  |  |    * different assets/playlists | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#crossOrigin | 
					
						
							|  |  |  |    * @return {string} | 
					
						
							|  |  |  |    *         - anonymous indicates that the media should not sent cookies. | 
					
						
							|  |  |  |    *         - use-credentials indicates that the media should sent cookies along the requests. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @see [Spec]{@link https://html.spec.whatwg.org/#attr-media-crossorigin}
 | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   'crossOrigin' | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | ].forEach(function(prop) { | 
					
						
							|  |  |  |   Html5.prototype[prop] = function() { | 
					
						
							|  |  |  |     return this.el_[prop]; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Wrap native properties with a setter in this format:
 | 
					
						
							|  |  |  | // set + toTitleCase(name)
 | 
					
						
							| 
									
										
										
										
											2017-08-15 17:02:07 -04:00
										 |  |  | // The list is as follows:
 | 
					
						
							| 
									
										
										
										
											2020-04-22 18:41:21 +02:00
										 |  |  | // setVolume, setSrc, setPoster, setPreload, setPlaybackRate, setDefaultPlaybackRate,
 | 
					
						
							|  |  |  | // setDisablePictureInPicture, setCrossOrigin
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | [ | 
					
						
							|  |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * 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. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#setVolume | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'volume', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * Set the value of `src` on the media element. `src` indicates the current | 
					
						
							|  |  |  |    * {@link Tech~SourceObject} for the media. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#setSrc | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'src', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * 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. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#setPoster | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'poster', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * 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 | 
					
						
							|  |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#setPreload | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @param {string} preload | 
					
						
							|  |  |  |    *         The value of `preload` to set on the media element. Must be 'none', 'metadata', | 
					
						
							|  |  |  |    *         or 'auto'. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'preload', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * 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. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#setPlaybackRate | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @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}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2017-01-18 14:59:15 -05:00
										 |  |  |   'playbackRate', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Set the value of `defaultPlaybackRate` on the media element. `defaultPlaybackRate` indicates | 
					
						
							|  |  |  |    * the rate at which the media should play back upon initial startup. Changing this value | 
					
						
							|  |  |  |    * after a video has started will do nothing. Instead you should used {@link Html5#setPlaybackRate}. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * Example Values: | 
					
						
							|  |  |  |    *   - 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 Html5.prototype.setDefaultPlaybackRate | 
					
						
							|  |  |  |    * @return {number} | 
					
						
							|  |  |  |    *         The value of `defaultPlaybackRate` 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-defaultplaybackrate}
 | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2020-04-06 08:53:45 -07:00
										 |  |  |   'defaultPlaybackRate', | 
					
						
							| 
									
										
										
										
											2017-01-18 14:59:15 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-22 18:41:21 +02:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Prevents the browser from suggesting a Picture-in-Picture context menu | 
					
						
							|  |  |  |    * or to request Picture-in-Picture automatically in some cases. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#setDisablePictureInPicture | 
					
						
							|  |  |  |    * @param {boolean} value | 
					
						
							|  |  |  |    *         The true value will disable Picture-in-Picture mode. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @see [Spec]{@link https://w3c.github.io/picture-in-picture/#disable-pip}
 | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   'disablePictureInPicture', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 08:53:45 -07:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Set the value of `crossOrigin` from the media element. `crossOrigin` indicates | 
					
						
							|  |  |  |    * to the browser that should sent the cookies along with the requests for the | 
					
						
							|  |  |  |    * different assets/playlists | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#setCrossOrigin | 
					
						
							|  |  |  |    * @param {string} crossOrigin | 
					
						
							|  |  |  |    *         - anonymous indicates that the media should not sent cookies. | 
					
						
							|  |  |  |    *         - use-credentials indicates that the media should sent cookies along the requests. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @see [Spec]{@link https://html.spec.whatwg.org/#attr-media-crossorigin}
 | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   'crossOrigin' | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | ].forEach(function(prop) { | 
					
						
							|  |  |  |   Html5.prototype['set' + toTitleCase(prop)] = function(v) { | 
					
						
							|  |  |  |     this.el_[prop] = v; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // wrap native functions with a function
 | 
					
						
							| 
									
										
										
										
											2017-08-15 17:02:07 -04:00
										 |  |  | // The list is as follows:
 | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  | // pause, load, play
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | [ | 
					
						
							|  |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * A wrapper around the media elements `pause` function. This will call the `HTML5` | 
					
						
							|  |  |  |    * media elements `pause` function. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#pause | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-pause}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							|  |  |  |   'pause', | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * A wrapper around the media elements `load` function. This will call the `HTML5`s | 
					
						
							|  |  |  |    * media element `load` function. | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-12-20 18:20:31 -05:00
										 |  |  |    * @method Html5#load | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |    * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-load}
 | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2017-01-18 00:53:11 -05:00
										 |  |  |   'load', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * A wrapper around the media elements `play` function. This will call the `HTML5`s | 
					
						
							|  |  |  |    * media element `play` function. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @method Html5#play | 
					
						
							|  |  |  |    * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-play}
 | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   'play' | 
					
						
							| 
									
										
										
										
											2016-09-29 14:26:37 -04:00
										 |  |  | ].forEach(function(prop) { | 
					
						
							|  |  |  |   Html5.prototype[prop] = function() { | 
					
						
							|  |  |  |     return this.el_[prop](); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:20:30 -04:00
										 |  |  | Tech.withSourceHandlers(Html5); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * Native source handler for Html5, simply passes the source to the media element. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |  * @property {Tech~SourceObject} source | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  *        The source object | 
					
						
							| 
									
										
										
										
											2016-10-19 18:20:30 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-04-10 22:34:20 +08:00
										 |  |  |  * @property {Html5} tech | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  *        The instance of the HTML5 tech. | 
					
						
							| 
									
										
										
										
											2016-10-19 18:20:30 -04:00
										 |  |  |  */ | 
					
						
							|  |  |  | Html5.nativeSourceHandler = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * Check if the media element can play the given mime type. | 
					
						
							| 
									
										
										
										
											2016-10-19 18:20:30 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * @param {string} type | 
					
						
							|  |  |  |  *        The mimetype to check | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @return {string} | 
					
						
							|  |  |  |  *         'probably', 'maybe', or '' (empty string) | 
					
						
							| 
									
										
										
										
											2016-10-19 18:20:30 -04:00
										 |  |  |  */ | 
					
						
							|  |  |  | Html5.nativeSourceHandler.canPlayType = function(type) { | 
					
						
							| 
									
										
										
										
											2018-03-23 13:25:12 -04:00
										 |  |  |   // IE without MediaPlayer throws an error (#519)
 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:20:30 -04:00
										 |  |  |   try { | 
					
						
							|  |  |  |     return Html5.TEST_VID.canPlayType(type); | 
					
						
							|  |  |  |   } catch (e) { | 
					
						
							|  |  |  |     return ''; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * 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. | 
					
						
							| 
									
										
										
										
											2016-10-19 18:20:30 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * @return {string} | 
					
						
							|  |  |  |  *         'probably', 'maybe', or '' (empty string). | 
					
						
							| 
									
										
										
										
											2016-10-19 18:20:30 -04:00
										 |  |  |  */ | 
					
						
							|  |  |  | Html5.nativeSourceHandler.canHandleSource = function(source, options) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // If a type was provided we should rely on that
 | 
					
						
							|  |  |  |   if (source.type) { | 
					
						
							|  |  |  |     return Html5.nativeSourceHandler.canPlayType(source.type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // If no type, fall back to checking 'video/[EXTENSION]'
 | 
					
						
							|  |  |  |   } else if (source.src) { | 
					
						
							|  |  |  |     const ext = Url.getFileExtension(source.src); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return Html5.nativeSourceHandler.canPlayType(`video/${ext}`); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ''; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * Pass the source to the native media element. | 
					
						
							| 
									
										
										
										
											2016-10-19 18:20:30 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  |  * @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 | 
					
						
							| 
									
										
										
										
											2016-10-19 18:20:30 -04:00
										 |  |  |  */ | 
					
						
							|  |  |  | Html5.nativeSourceHandler.handleSource = function(source, tech, options) { | 
					
						
							|  |  |  |   tech.setSrc(source.src); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-02 15:14:36 -05:00
										 |  |  | /** | 
					
						
							|  |  |  |  * A noop for the native dispose function, as cleanup is not needed. | 
					
						
							| 
									
										
										
										
											2016-10-19 18:20:30 -04:00
										 |  |  |  */ | 
					
						
							|  |  |  | Html5.nativeSourceHandler.dispose = function() {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Register the native source handler
 | 
					
						
							|  |  |  | Html5.registerSourceHandler(Html5.nativeSourceHandler); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-09 14:12:57 -05:00
										 |  |  | Tech.registerTech('Html5', Html5); | 
					
						
							| 
									
										
										
										
											2015-04-14 13:08:32 -07:00
										 |  |  | export default Html5; |