Security update for Core, with self-updated composer
[yaffs-website] / node_modules / video.js / es5 / tech / html5.js
1 'use strict';
2
3 exports.__esModule = true;
4
5 var _templateObject = _taggedTemplateLiteralLoose(['Text Tracks are being loaded from another origin but the crossorigin attribute isn\'t used.\n            This may prevent text tracks from loading.'], ['Text Tracks are being loaded from another origin but the crossorigin attribute isn\'t used.\n            This may prevent text tracks from loading.']);
6
7 var _tech = require('./tech.js');
8
9 var _tech2 = _interopRequireDefault(_tech);
10
11 var _component = require('../component');
12
13 var _component2 = _interopRequireDefault(_component);
14
15 var _dom = require('../utils/dom.js');
16
17 var Dom = _interopRequireWildcard(_dom);
18
19 var _url = require('../utils/url.js');
20
21 var Url = _interopRequireWildcard(_url);
22
23 var _fn = require('../utils/fn.js');
24
25 var Fn = _interopRequireWildcard(_fn);
26
27 var _log = require('../utils/log.js');
28
29 var _log2 = _interopRequireDefault(_log);
30
31 var _tsml = require('tsml');
32
33 var _tsml2 = _interopRequireDefault(_tsml);
34
35 var _browser = require('../utils/browser.js');
36
37 var browser = _interopRequireWildcard(_browser);
38
39 var _document = require('global/document');
40
41 var _document2 = _interopRequireDefault(_document);
42
43 var _window = require('global/window');
44
45 var _window2 = _interopRequireDefault(_window);
46
47 var _obj = require('../utils/obj');
48
49 var _mergeOptions = require('../utils/merge-options.js');
50
51 var _mergeOptions2 = _interopRequireDefault(_mergeOptions);
52
53 var _toTitleCase = require('../utils/to-title-case.js');
54
55 var _toTitleCase2 = _interopRequireDefault(_toTitleCase);
56
57 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
58
59 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
60
61 function _taggedTemplateLiteralLoose(strings, raw) { strings.raw = raw; return strings; }
62
63 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
64
65 function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
66
67 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
68                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 * @file html5.js
69                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 */
70
71
72 /**
73  * HTML5 Media Controller - Wrapper for HTML5 Media API
74  *
75  * @mixes Tech~SouceHandlerAdditions
76  * @extends Tech
77  */
78 var Html5 = function (_Tech) {
79   _inherits(Html5, _Tech);
80
81   /**
82    * Create an instance of this Tech.
83    *
84    * @param {Object} [options]
85    *        The key/value store of player options.
86    *
87    * @param {Component~ReadyCallback} ready
88    *        Callback function to call when the `HTML5` Tech is ready.
89    */
90   function Html5(options, ready) {
91     _classCallCheck(this, Html5);
92
93     var _this = _possibleConstructorReturn(this, _Tech.call(this, options, ready));
94
95     var source = options.source;
96     var crossoriginTracks = false;
97
98     // Set the source if one is provided
99     // 1) Check if the source is new (if not, we want to keep the original so playback isn't interrupted)
100     // 2) Check to see if the network state of the tag was failed at init, and if so, reset the source
101     // anyway so the error gets fired.
102     if (source && (_this.el_.currentSrc !== source.src || options.tag && options.tag.initNetworkState_ === 3)) {
103       _this.setSource(source);
104     } else {
105       _this.handleLateInit_(_this.el_);
106     }
107
108     if (_this.el_.hasChildNodes()) {
109
110       var nodes = _this.el_.childNodes;
111       var nodesLength = nodes.length;
112       var removeNodes = [];
113
114       while (nodesLength--) {
115         var node = nodes[nodesLength];
116         var nodeName = node.nodeName.toLowerCase();
117
118         if (nodeName === 'track') {
119           if (!_this.featuresNativeTextTracks) {
120             // Empty video tag tracks so the built-in player doesn't use them also.
121             // This may not be fast enough to stop HTML5 browsers from reading the tags
122             // so we'll need to turn off any default tracks if we're manually doing
123             // captions and subtitles. videoElement.textTracks
124             removeNodes.push(node);
125           } else {
126             // store HTMLTrackElement and TextTrack to remote list
127             _this.remoteTextTrackEls().addTrackElement_(node);
128             _this.remoteTextTracks().addTrack_(node.track);
129             if (!crossoriginTracks && !_this.el_.hasAttribute('crossorigin') && Url.isCrossOrigin(node.src)) {
130               crossoriginTracks = true;
131             }
132           }
133         }
134       }
135
136       for (var i = 0; i < removeNodes.length; i++) {
137         _this.el_.removeChild(removeNodes[i]);
138       }
139     }
140
141     // TODO: add text tracks into this list
142     var trackTypes = ['audio', 'video'];
143
144     // ProxyNative Video/Audio Track
145     trackTypes.forEach(function (type) {
146       var elTracks = _this.el()[type + 'Tracks'];
147       var techTracks = _this[type + 'Tracks']();
148       var capitalType = (0, _toTitleCase2['default'])(type);
149
150       if (!_this['featuresNative' + capitalType + 'Tracks'] || !elTracks || !elTracks.addEventListener) {
151         return;
152       }
153
154       _this['handle' + capitalType + 'TrackChange_'] = function (e) {
155         techTracks.trigger({
156           type: 'change',
157           target: techTracks,
158           currentTarget: techTracks,
159           srcElement: techTracks
160         });
161       };
162
163       _this['handle' + capitalType + 'TrackAdd_'] = function (e) {
164         return techTracks.addTrack(e.track);
165       };
166       _this['handle' + capitalType + 'TrackRemove_'] = function (e) {
167         return techTracks.removeTrack(e.track);
168       };
169
170       elTracks.addEventListener('change', _this['handle' + capitalType + 'TrackChange_']);
171       elTracks.addEventListener('addtrack', _this['handle' + capitalType + 'TrackAdd_']);
172       elTracks.addEventListener('removetrack', _this['handle' + capitalType + 'TrackRemove_']);
173       _this['removeOld' + capitalType + 'Tracks_'] = function (e) {
174         return _this.removeOldTracks_(techTracks, elTracks);
175       };
176
177       // Remove (native) tracks that are not used anymore
178       _this.on('loadstart', _this['removeOld' + capitalType + 'Tracks_']);
179     });
180
181     if (_this.featuresNativeTextTracks) {
182       if (crossoriginTracks) {
183         _log2['default'].warn((0, _tsml2['default'])(_templateObject));
184       }
185
186       _this.handleTextTrackChange_ = Fn.bind(_this, _this.handleTextTrackChange);
187       _this.handleTextTrackAdd_ = Fn.bind(_this, _this.handleTextTrackAdd);
188       _this.handleTextTrackRemove_ = Fn.bind(_this, _this.handleTextTrackRemove);
189       _this.proxyNativeTextTracks_();
190     }
191
192     // Determine if native controls should be used
193     // Our goal should be to get the custom controls on mobile solid everywhere
194     // so we can remove this all together. Right now this will block custom
195     // controls on touch enabled laptops like the Chrome Pixel
196     if ((browser.TOUCH_ENABLED || browser.IS_IPHONE || browser.IS_NATIVE_ANDROID) && options.nativeControlsForTouch === true) {
197       _this.setControls(true);
198     }
199
200     // on iOS, we want to proxy `webkitbeginfullscreen` and `webkitendfullscreen`
201     // into a `fullscreenchange` event
202     _this.proxyWebkitFullscreen_();
203
204     _this.triggerReady();
205     return _this;
206   }
207
208   /**
209    * Dispose of `HTML5` media element and remove all tracks.
210    */
211
212
213   Html5.prototype.dispose = function dispose() {
214     var _this2 = this;
215
216     // Un-ProxyNativeTracks
217     ['audio', 'video', 'text'].forEach(function (type) {
218       var capitalType = (0, _toTitleCase2['default'])(type);
219       var tl = _this2.el_[type + 'Tracks'];
220
221       if (tl && tl.removeEventListener) {
222         tl.removeEventListener('change', _this2['handle' + capitalType + 'TrackChange_']);
223         tl.removeEventListener('addtrack', _this2['handle' + capitalType + 'TrackAdd_']);
224         tl.removeEventListener('removetrack', _this2['handle' + capitalType + 'TrackRemove_']);
225       }
226
227       // Stop removing old text tracks
228       if (tl) {
229         _this2.off('loadstart', _this2['removeOld' + capitalType + 'Tracks_']);
230       }
231     });
232
233     Html5.disposeMediaElement(this.el_);
234     // tech will handle clearing of the emulated track list
235     _Tech.prototype.dispose.call(this);
236   };
237
238   /**
239    * Create the `Html5` Tech's DOM element.
240    *
241    * @return {Element}
242    *         The element that gets created.
243    */
244
245
246   Html5.prototype.createEl = function createEl() {
247     var el = this.options_.tag;
248
249     // Check if this browser supports moving the element into the box.
250     // On the iPhone video will break if you move the element,
251     // So we have to create a brand new element.
252     // If we ingested the player div, we do not need to move the media element.
253     if (!el || !(this.options_.playerElIngest || this.movingMediaElementInDOM)) {
254
255       // If the original tag is still there, clone and remove it.
256       if (el) {
257         var clone = el.cloneNode(true);
258
259         if (el.parentNode) {
260           el.parentNode.insertBefore(clone, el);
261         }
262         Html5.disposeMediaElement(el);
263         el = clone;
264       } else {
265         el = _document2['default'].createElement('video');
266
267         // determine if native controls should be used
268         var tagAttributes = this.options_.tag && Dom.getElAttributes(this.options_.tag);
269         var attributes = (0, _mergeOptions2['default'])({}, tagAttributes);
270
271         if (!browser.TOUCH_ENABLED || this.options_.nativeControlsForTouch !== true) {
272           delete attributes.controls;
273         }
274
275         Dom.setElAttributes(el, (0, _obj.assign)(attributes, {
276           id: this.options_.techId,
277           'class': 'vjs-tech'
278         }));
279       }
280
281       el.playerId = this.options_.playerId;
282     }
283
284     // Update specific tag settings, in case they were overridden
285     var settingsAttrs = ['autoplay', 'preload', 'loop', 'muted'];
286
287     for (var i = settingsAttrs.length - 1; i >= 0; i--) {
288       var attr = settingsAttrs[i];
289       var overwriteAttrs = {};
290
291       if (typeof this.options_[attr] !== 'undefined') {
292         overwriteAttrs[attr] = this.options_[attr];
293       }
294       Dom.setElAttributes(el, overwriteAttrs);
295     }
296
297     return el;
298   };
299
300   /**
301    * This will be triggered if the loadstart event has already fired, before videojs was
302    * ready. Two known examples of when this can happen are:
303    * 1. If we're loading the playback object after it has started loading
304    * 2. The media is already playing the (often with autoplay on) then
305    *
306    * This function will fire another loadstart so that videojs can catchup.
307    *
308    * @fires Tech#loadstart
309    *
310    * @return {undefined}
311    *         returns nothing.
312    */
313
314
315   Html5.prototype.handleLateInit_ = function handleLateInit_(el) {
316     if (el.networkState === 0 || el.networkState === 3) {
317       // The video element hasn't started loading the source yet
318       // or didn't find a source
319       return;
320     }
321
322     if (el.readyState === 0) {
323       // NetworkState is set synchronously BUT loadstart is fired at the
324       // end of the current stack, usually before setInterval(fn, 0).
325       // So at this point we know loadstart may have already fired or is
326       // about to fire, and either way the player hasn't seen it yet.
327       // We don't want to fire loadstart prematurely here and cause a
328       // double loadstart so we'll wait and see if it happens between now
329       // and the next loop, and fire it if not.
330       // HOWEVER, we also want to make sure it fires before loadedmetadata
331       // which could also happen between now and the next loop, so we'll
332       // watch for that also.
333       var loadstartFired = false;
334       var setLoadstartFired = function setLoadstartFired() {
335         loadstartFired = true;
336       };
337
338       this.on('loadstart', setLoadstartFired);
339
340       var triggerLoadstart = function triggerLoadstart() {
341         // We did miss the original loadstart. Make sure the player
342         // sees loadstart before loadedmetadata
343         if (!loadstartFired) {
344           this.trigger('loadstart');
345         }
346       };
347
348       this.on('loadedmetadata', triggerLoadstart);
349
350       this.ready(function () {
351         this.off('loadstart', setLoadstartFired);
352         this.off('loadedmetadata', triggerLoadstart);
353
354         if (!loadstartFired) {
355           // We did miss the original native loadstart. Fire it now.
356           this.trigger('loadstart');
357         }
358       });
359
360       return;
361     }
362
363     // From here on we know that loadstart already fired and we missed it.
364     // The other readyState events aren't as much of a problem if we double
365     // them, so not going to go to as much trouble as loadstart to prevent
366     // that unless we find reason to.
367     var eventsToTrigger = ['loadstart'];
368
369     // loadedmetadata: newly equal to HAVE_METADATA (1) or greater
370     eventsToTrigger.push('loadedmetadata');
371
372     // loadeddata: newly increased to HAVE_CURRENT_DATA (2) or greater
373     if (el.readyState >= 2) {
374       eventsToTrigger.push('loadeddata');
375     }
376
377     // canplay: newly increased to HAVE_FUTURE_DATA (3) or greater
378     if (el.readyState >= 3) {
379       eventsToTrigger.push('canplay');
380     }
381
382     // canplaythrough: newly equal to HAVE_ENOUGH_DATA (4)
383     if (el.readyState >= 4) {
384       eventsToTrigger.push('canplaythrough');
385     }
386
387     // We still need to give the player time to add event listeners
388     this.ready(function () {
389       eventsToTrigger.forEach(function (type) {
390         this.trigger(type);
391       }, this);
392     });
393   };
394
395   /**
396    * Add event listeners to native text track events. This adds the native text tracks
397    * to our emulated {@link TextTrackList}.
398    */
399
400
401   Html5.prototype.proxyNativeTextTracks_ = function proxyNativeTextTracks_() {
402     var tt = this.el().textTracks;
403
404     if (tt) {
405       // Add tracks - if player is initialised after DOM loaded, textTracks
406       // will not trigger addtrack
407       for (var i = 0; i < tt.length; i++) {
408         this.textTracks().addTrack_(tt[i]);
409       }
410
411       if (tt.addEventListener) {
412         tt.addEventListener('change', this.handleTextTrackChange_);
413         tt.addEventListener('addtrack', this.handleTextTrackAdd_);
414         tt.addEventListener('removetrack', this.handleTextTrackRemove_);
415       }
416
417       // Remove (native) texttracks that are not used anymore
418       this.on('loadstart', this.removeOldTextTracks_);
419     }
420   };
421
422   /**
423    * Handle any {@link TextTrackList} `change` event.
424    *
425    * @param {EventTarget~Event} e
426    *        The `change` event that caused this to run.
427    *
428    * @listens TextTrackList#change
429    */
430
431
432   Html5.prototype.handleTextTrackChange = function handleTextTrackChange(e) {
433     var tt = this.textTracks();
434
435     this.textTracks().trigger({
436       type: 'change',
437       target: tt,
438       currentTarget: tt,
439       srcElement: tt
440     });
441   };
442
443   /**
444    * Handle any {@link TextTrackList} `addtrack` event.
445    *
446    * @param {EventTarget~Event} e
447    *        The `addtrack` event that caused this to run.
448    *
449    * @listens TextTrackList#addtrack
450    */
451
452
453   Html5.prototype.handleTextTrackAdd = function handleTextTrackAdd(e) {
454     this.textTracks().addTrack_(e.track);
455   };
456
457   /**
458    * Handle any {@link TextTrackList} `removetrack` event.
459    *
460    * @param {EventTarget~Event} e
461    *        The `removetrack` event that caused this to run.
462    *
463    * @listens TextTrackList#removetrack
464    */
465
466
467   Html5.prototype.handleTextTrackRemove = function handleTextTrackRemove(e) {
468     this.textTracks().removeTrack_(e.track);
469   };
470
471   /**
472    * This function removes any {@link AudioTrack}s, {@link VideoTrack}s, or
473    * {@link TextTrack}s that are not in the media elements TrackList.
474    *
475    * @param {TrackList} techTracks
476    *        HTML5 Tech's TrackList to search through
477    *
478    * @param {TrackList} elTracks
479    *        HTML5 media elements TrackList to search trough.
480    *
481    * @private
482    */
483
484
485   Html5.prototype.removeOldTracks_ = function removeOldTracks_(techTracks, elTracks) {
486     // This will loop over the techTracks and check if they are still used by the HTML5 media element
487     // If not, they will be removed from the emulated list
488     var removeTracks = [];
489
490     if (!elTracks) {
491       return;
492     }
493
494     for (var i = 0; i < techTracks.length; i++) {
495       var techTrack = techTracks[i];
496       var found = false;
497
498       for (var j = 0; j < elTracks.length; j++) {
499         if (elTracks[j] === techTrack) {
500           found = true;
501           break;
502         }
503       }
504
505       if (!found) {
506         removeTracks.push(techTrack);
507       }
508     }
509
510     for (var _i = 0; _i < removeTracks.length; _i++) {
511       var track = removeTracks[_i];
512
513       techTracks.removeTrack_(track);
514     }
515   };
516
517   /**
518    * Remove {@link TextTrack}s that dont exist in the native track list from our
519    * emulated {@link TextTrackList}.
520    *
521    * @listens Tech#loadstart
522    */
523
524
525   Html5.prototype.removeOldTextTracks_ = function removeOldTextTracks_(e) {
526     var techTracks = this.textTracks();
527     var elTracks = this.el().textTracks;
528
529     this.removeOldTracks_(techTracks, elTracks);
530   };
531
532   /**
533    * Called by {@link Player#play} to play using the `Html5` `Tech`.
534    */
535
536
537   Html5.prototype.play = function play() {
538     var playPromise = this.el_.play();
539
540     // Catch/silence error when a pause interrupts a play request
541     // on browsers which return a promise
542     if (playPromise !== undefined && typeof playPromise.then === 'function') {
543       playPromise.then(null, function (e) {});
544     }
545   };
546
547   /**
548    * Set current time for the `HTML5` tech.
549    *
550    * @param {number} seconds
551    *        Set the current time of the media to this.
552    */
553
554
555   Html5.prototype.setCurrentTime = function setCurrentTime(seconds) {
556     try {
557       this.el_.currentTime = seconds;
558     } catch (e) {
559       (0, _log2['default'])(e, 'Video is not ready. (Video.js)');
560       // this.warning(VideoJS.warnings.videoNotReady);
561     }
562   };
563
564   /**
565    * Get the current duration of the HTML5 media element.
566    *
567    * @return {number}
568    *         The duration of the media or 0 if there is no duration.
569    */
570
571
572   Html5.prototype.duration = function duration() {
573     var _this3 = this;
574
575     // Android Chrome will report duration as Infinity for VOD HLS until after
576     // playback has started, which triggers the live display erroneously.
577     // Return NaN if playback has not started and trigger a durationupdate once
578     // the duration can be reliably known.
579     if (this.el_.duration === Infinity && browser.IS_ANDROID && browser.IS_CHROME) {
580       if (this.el_.currentTime === 0) {
581         // Wait for the first `timeupdate` with currentTime > 0 - there may be
582         // several with 0
583         var checkProgress = function checkProgress() {
584           if (_this3.el_.currentTime > 0) {
585             // Trigger durationchange for genuinely live video
586             if (_this3.el_.duration === Infinity) {
587               _this3.trigger('durationchange');
588             }
589             _this3.off('timeupdate', checkProgress);
590           }
591         };
592
593         this.on('timeupdate', checkProgress);
594         return NaN;
595       }
596     }
597     return this.el_.duration || NaN;
598   };
599
600   /**
601    * Get the current width of the HTML5 media element.
602    *
603    * @return {number}
604    *         The width of the HTML5 media element.
605    */
606
607
608   Html5.prototype.width = function width() {
609     return this.el_.offsetWidth;
610   };
611
612   /**
613    * Get the current height of the HTML5 media element.
614    *
615    * @return {number}
616    *         The heigth of the HTML5 media element.
617    */
618
619
620   Html5.prototype.height = function height() {
621     return this.el_.offsetHeight;
622   };
623
624   /**
625    * Proxy iOS `webkitbeginfullscreen` and `webkitendfullscreen` into
626    * `fullscreenchange` event.
627    *
628    * @private
629    * @fires fullscreenchange
630    * @listens webkitendfullscreen
631    * @listens webkitbeginfullscreen
632    * @listens webkitbeginfullscreen
633    */
634
635
636   Html5.prototype.proxyWebkitFullscreen_ = function proxyWebkitFullscreen_() {
637     var _this4 = this;
638
639     if (!('webkitDisplayingFullscreen' in this.el_)) {
640       return;
641     }
642
643     var endFn = function endFn() {
644       this.trigger('fullscreenchange', { isFullscreen: false });
645     };
646
647     var beginFn = function beginFn() {
648       this.one('webkitendfullscreen', endFn);
649
650       this.trigger('fullscreenchange', { isFullscreen: true });
651     };
652
653     this.on('webkitbeginfullscreen', beginFn);
654     this.on('dispose', function () {
655       _this4.off('webkitbeginfullscreen', beginFn);
656       _this4.off('webkitendfullscreen', endFn);
657     });
658   };
659
660   /**
661    * Check if fullscreen is supported on the current playback device.
662    *
663    * @return {boolean}
664    *         - True if fullscreen is supported.
665    *         - False if fullscreen is not supported.
666    */
667
668
669   Html5.prototype.supportsFullScreen = function supportsFullScreen() {
670     if (typeof this.el_.webkitEnterFullScreen === 'function') {
671       var userAgent = _window2['default'].navigator && _window2['default'].navigator.userAgent || '';
672
673       // Seems to be broken in Chromium/Chrome && Safari in Leopard
674       if (/Android/.test(userAgent) || !/Chrome|Mac OS X 10.5/.test(userAgent)) {
675         return true;
676       }
677     }
678     return false;
679   };
680
681   /**
682    * Request that the `HTML5` Tech enter fullscreen.
683    */
684
685
686   Html5.prototype.enterFullScreen = function enterFullScreen() {
687     var video = this.el_;
688
689     if (video.paused && video.networkState <= video.HAVE_METADATA) {
690       // attempt to prime the video element for programmatic access
691       // this isn't necessary on the desktop but shouldn't hurt
692       this.el_.play();
693
694       // playing and pausing synchronously during the transition to fullscreen
695       // can get iOS ~6.1 devices into a play/pause loop
696       this.setTimeout(function () {
697         video.pause();
698         video.webkitEnterFullScreen();
699       }, 0);
700     } else {
701       video.webkitEnterFullScreen();
702     }
703   };
704
705   /**
706    * Request that the `HTML5` Tech exit fullscreen.
707    */
708
709
710   Html5.prototype.exitFullScreen = function exitFullScreen() {
711     this.el_.webkitExitFullScreen();
712   };
713
714   /**
715    * A getter/setter for the `Html5` Tech's source object.
716    * > Note: Please use {@link Html5#setSource}
717    *
718    * @param {Tech~SourceObject} [src]
719    *        The source object you want to set on the `HTML5` techs element.
720    *
721    * @return {Tech~SourceObject|undefined}
722    *         - The current source object when a source is not passed in.
723    *         - undefined when setting
724    *
725    * @deprecated Since version 5.
726    */
727
728
729   Html5.prototype.src = function src(_src) {
730     if (_src === undefined) {
731       return this.el_.src;
732     }
733
734     // Setting src through `src` instead of `setSrc` will be deprecated
735     this.setSrc(_src);
736   };
737
738   /**
739    * Reset the tech by removing all sources and then calling
740    * {@link Html5.resetMediaElement}.
741    */
742
743
744   Html5.prototype.reset = function reset() {
745     Html5.resetMediaElement(this.el_);
746   };
747
748   /**
749    * Get the current source on the `HTML5` Tech. Falls back to returning the source from
750    * the HTML5 media element.
751    *
752    * @return {Tech~SourceObject}
753    *         The current source object from the HTML5 tech. With a fallback to the
754    *         elements source.
755    */
756
757
758   Html5.prototype.currentSrc = function currentSrc() {
759     if (this.currentSource_) {
760       return this.currentSource_.src;
761     }
762     return this.el_.currentSrc;
763   };
764
765   /**
766    * Set controls attribute for the HTML5 media Element.
767    *
768    * @param {string} val
769    *        Value to set the controls attribute to
770    */
771
772
773   Html5.prototype.setControls = function setControls(val) {
774     this.el_.controls = !!val;
775   };
776
777   /**
778    * Create and returns a remote {@link TextTrack} object.
779    *
780    * @param {string} kind
781    *        `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)
782    *
783    * @param {string} [label]
784    *        Label to identify the text track
785    *
786    * @param {string} [language]
787    *        Two letter language abbreviation
788    *
789    * @return {TextTrack}
790    *         The TextTrack that gets created.
791    */
792
793
794   Html5.prototype.addTextTrack = function addTextTrack(kind, label, language) {
795     if (!this.featuresNativeTextTracks) {
796       return _Tech.prototype.addTextTrack.call(this, kind, label, language);
797     }
798
799     return this.el_.addTextTrack(kind, label, language);
800   };
801
802   /**
803    * Creates either native TextTrack or an emulated TextTrack depending
804    * on the value of `featuresNativeTextTracks`
805    *
806    * @param {Object} options
807    *        The object should contain the options to intialize the TextTrack with.
808    *
809    * @param {string} [options.kind]
810    *        `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata).
811    *
812    * @param {string} [options.label].
813    *        Label to identify the text track
814    *
815    * @param {string} [options.language]
816    *        Two letter language abbreviation.
817    *
818    * @param {boolean} [options.default]
819    *        Default this track to on.
820    *
821    * @param {string} [options.id]
822    *        The internal id to assign this track.
823    *
824    * @param {string} [options.src]
825    *        A source url for the track.
826    *
827    * @return {HTMLTrackElement}
828    *         The track element that gets created.
829    */
830
831
832   Html5.prototype.createRemoteTextTrack = function createRemoteTextTrack(options) {
833     if (!this.featuresNativeTextTracks) {
834       return _Tech.prototype.createRemoteTextTrack.call(this, options);
835     }
836     var htmlTrackElement = _document2['default'].createElement('track');
837
838     if (options.kind) {
839       htmlTrackElement.kind = options.kind;
840     }
841     if (options.label) {
842       htmlTrackElement.label = options.label;
843     }
844     if (options.language || options.srclang) {
845       htmlTrackElement.srclang = options.language || options.srclang;
846     }
847     if (options['default']) {
848       htmlTrackElement['default'] = options['default'];
849     }
850     if (options.id) {
851       htmlTrackElement.id = options.id;
852     }
853     if (options.src) {
854       htmlTrackElement.src = options.src;
855     }
856
857     return htmlTrackElement;
858   };
859
860   /**
861    * Creates a remote text track object and returns an html track element.
862    *
863    * @param {Object} options The object should contain values for
864    * kind, language, label, and src (location of the WebVTT file)
865    * @param {Boolean} [manualCleanup=true] if set to false, the TextTrack will be
866    * automatically removed from the video element whenever the source changes
867    * @return {HTMLTrackElement} An Html Track Element.
868    * This can be an emulated {@link HTMLTrackElement} or a native one.
869    * @deprecated The default value of the "manualCleanup" parameter will default
870    * to "false" in upcoming versions of Video.js
871    */
872
873
874   Html5.prototype.addRemoteTextTrack = function addRemoteTextTrack(options, manualCleanup) {
875     var htmlTrackElement = _Tech.prototype.addRemoteTextTrack.call(this, options, manualCleanup);
876
877     if (this.featuresNativeTextTracks) {
878       this.el().appendChild(htmlTrackElement);
879     }
880
881     return htmlTrackElement;
882   };
883
884   /**
885    * Remove remote `TextTrack` from `TextTrackList` object
886    *
887    * @param {TextTrack} track
888    *        `TextTrack` object to remove
889    */
890
891
892   Html5.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) {
893     _Tech.prototype.removeRemoteTextTrack.call(this, track);
894
895     if (this.featuresNativeTextTracks) {
896       var tracks = this.$$('track');
897
898       var i = tracks.length;
899
900       while (i--) {
901         if (track === tracks[i] || track === tracks[i].track) {
902           this.el().removeChild(tracks[i]);
903         }
904       }
905     }
906   };
907
908   return Html5;
909 }(_tech2['default']);
910
911 /* HTML5 Support Testing ---------------------------------------------------- */
912
913 if (Dom.isReal()) {
914
915   /**
916    * Element for testing browser HTML5 media capabilities
917    *
918    * @type {Element}
919    * @constant
920    * @private
921    */
922   Html5.TEST_VID = _document2['default'].createElement('video');
923   var track = _document2['default'].createElement('track');
924
925   track.kind = 'captions';
926   track.srclang = 'en';
927   track.label = 'English';
928   Html5.TEST_VID.appendChild(track);
929 }
930
931 /**
932  * Check if HTML5 media is supported by this browser/device.
933  *
934  * @return {boolean}
935  *         - True if HTML5 media is supported.
936  *         - False if HTML5 media is not supported.
937  */
938 Html5.isSupported = function () {
939   // IE9 with no Media Player is a LIAR! (#984)
940   try {
941     Html5.TEST_VID.volume = 0.5;
942   } catch (e) {
943     return false;
944   }
945
946   return !!(Html5.TEST_VID && Html5.TEST_VID.canPlayType);
947 };
948
949 /**
950  * Check if the volume can be changed in this browser/device.
951  * Volume cannot be changed in a lot of mobile devices.
952  * Specifically, it can't be changed from 1 on iOS.
953  *
954  * @return {boolean}
955  *         - True if volume can be controlled
956  *         - False otherwise
957  */
958 Html5.canControlVolume = function () {
959   // IE will error if Windows Media Player not installed #3315
960   try {
961     var volume = Html5.TEST_VID.volume;
962
963     Html5.TEST_VID.volume = volume / 2 + 0.1;
964     return volume !== Html5.TEST_VID.volume;
965   } catch (e) {
966     return false;
967   }
968 };
969
970 /**
971  * Check if the playback rate can be changed in this browser/device.
972  *
973  * @return {boolean}
974  *         - True if playback rate can be controlled
975  *         - False otherwise
976  */
977 Html5.canControlPlaybackRate = function () {
978   // Playback rate API is implemented in Android Chrome, but doesn't do anything
979   // https://github.com/videojs/video.js/issues/3180
980   if (browser.IS_ANDROID && browser.IS_CHROME) {
981     return false;
982   }
983   // IE will error if Windows Media Player not installed #3315
984   try {
985     var playbackRate = Html5.TEST_VID.playbackRate;
986
987     Html5.TEST_VID.playbackRate = playbackRate / 2 + 0.1;
988     return playbackRate !== Html5.TEST_VID.playbackRate;
989   } catch (e) {
990     return false;
991   }
992 };
993
994 /**
995  * Check to see if native `TextTrack`s are supported by this browser/device.
996  *
997  * @return {boolean}
998  *         - True if native `TextTrack`s are supported.
999  *         - False otherwise
1000  */
1001 Html5.supportsNativeTextTracks = function () {
1002   return browser.IS_ANY_SAFARI;
1003 };
1004
1005 /**
1006  * Check to see if native `VideoTrack`s are supported by this browser/device
1007  *
1008  * @return {boolean}
1009  *        - True if native `VideoTrack`s are supported.
1010  *        - False otherwise
1011  */
1012 Html5.supportsNativeVideoTracks = function () {
1013   return !!(Html5.TEST_VID && Html5.TEST_VID.videoTracks);
1014 };
1015
1016 /**
1017  * Check to see if native `AudioTrack`s are supported by this browser/device
1018  *
1019  * @return {boolean}
1020  *        - True if native `AudioTrack`s are supported.
1021  *        - False otherwise
1022  */
1023 Html5.supportsNativeAudioTracks = function () {
1024   return !!(Html5.TEST_VID && Html5.TEST_VID.audioTracks);
1025 };
1026
1027 /**
1028  * An array of events available on the Html5 tech.
1029  *
1030  * @private
1031  * @type {Array}
1032  */
1033 Html5.Events = ['loadstart', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'waiting', 'seeking', 'seeked', 'ended', 'durationchange', 'timeupdate', 'progress', 'play', 'pause', 'ratechange', 'volumechange'];
1034
1035 /**
1036  * Boolean indicating whether the `Tech` supports volume control.
1037  *
1038  * @type {boolean}
1039  * @default {@link Html5.canControlVolume}
1040  */
1041 Html5.prototype.featuresVolumeControl = Html5.canControlVolume();
1042
1043 /**
1044  * Boolean indicating whether the `Tech` supports changing the speed at which the media
1045  * plays. Examples:
1046  *   - Set player to play 2x (twice) as fast
1047  *   - Set player to play 0.5x (half) as fast
1048  *
1049  * @type {boolean}
1050  * @default {@link Html5.canControlPlaybackRate}
1051  */
1052 Html5.prototype.featuresPlaybackRate = Html5.canControlPlaybackRate();
1053
1054 /**
1055  * Boolean indicating whether the `HTML5` tech currently supports the media element
1056  * moving in the DOM. iOS breaks if you move the media element, so this is set this to
1057  * false there. Everywhere else this should be true.
1058  *
1059  * @type {boolean}
1060  * @default
1061  */
1062 Html5.prototype.movingMediaElementInDOM = !browser.IS_IOS;
1063
1064 // TODO: Previous comment: No longer appears to be used. Can probably be removed.
1065 //       Is this true?
1066 /**
1067  * Boolean indicating whether the `HTML5` tech currently supports automatic media resize
1068  * when going into fullscreen.
1069  *
1070  * @type {boolean}
1071  * @default
1072  */
1073 Html5.prototype.featuresFullscreenResize = true;
1074
1075 /**
1076  * Boolean indicating whether the `HTML5` tech currently supports the progress event.
1077  * If this is false, manual `progress` events will be triggred instead.
1078  *
1079  * @type {boolean}
1080  * @default
1081  */
1082 Html5.prototype.featuresProgressEvents = true;
1083
1084 /**
1085  * Boolean indicating whether the `HTML5` tech currently supports the timeupdate event.
1086  * If this is false, manual `timeupdate` events will be triggred instead.
1087  *
1088  * @default
1089  */
1090 Html5.prototype.featuresTimeupdateEvents = true;
1091
1092 /**
1093  * Boolean indicating whether the `HTML5` tech currently supports native `TextTrack`s.
1094  *
1095  * @type {boolean}
1096  * @default {@link Html5.supportsNativeTextTracks}
1097  */
1098 Html5.prototype.featuresNativeTextTracks = Html5.supportsNativeTextTracks();
1099
1100 /**
1101  * Boolean indicating whether the `HTML5` tech currently supports native `VideoTrack`s.
1102  *
1103  * @type {boolean}
1104  * @default {@link Html5.supportsNativeVideoTracks}
1105  */
1106 Html5.prototype.featuresNativeVideoTracks = Html5.supportsNativeVideoTracks();
1107
1108 /**
1109  * Boolean indicating whether the `HTML5` tech currently supports native `AudioTrack`s.
1110  *
1111  * @type {boolean}
1112  * @default {@link Html5.supportsNativeAudioTracks}
1113  */
1114 Html5.prototype.featuresNativeAudioTracks = Html5.supportsNativeAudioTracks();
1115
1116 // HTML5 Feature detection and Device Fixes --------------------------------- //
1117 var canPlayType = Html5.TEST_VID && Html5.TEST_VID.constructor.prototype.canPlayType;
1118 var mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i;
1119 var mp4RE = /^video\/mp4/i;
1120
1121 Html5.patchCanPlayType = function () {
1122
1123   // Android 4.0 and above can play HLS to some extent but it reports being unable to do so
1124   if (browser.ANDROID_VERSION >= 4.0 && !browser.IS_FIREFOX) {
1125     Html5.TEST_VID.constructor.prototype.canPlayType = function (type) {
1126       if (type && mpegurlRE.test(type)) {
1127         return 'maybe';
1128       }
1129       return canPlayType.call(this, type);
1130     };
1131
1132     // Override Android 2.2 and less canPlayType method which is broken
1133   } else if (browser.IS_OLD_ANDROID) {
1134     Html5.TEST_VID.constructor.prototype.canPlayType = function (type) {
1135       if (type && mp4RE.test(type)) {
1136         return 'maybe';
1137       }
1138       return canPlayType.call(this, type);
1139     };
1140   }
1141 };
1142
1143 Html5.unpatchCanPlayType = function () {
1144   var r = Html5.TEST_VID.constructor.prototype.canPlayType;
1145
1146   Html5.TEST_VID.constructor.prototype.canPlayType = canPlayType;
1147   return r;
1148 };
1149
1150 // by default, patch the media element
1151 Html5.patchCanPlayType();
1152
1153 Html5.disposeMediaElement = function (el) {
1154   if (!el) {
1155     return;
1156   }
1157
1158   if (el.parentNode) {
1159     el.parentNode.removeChild(el);
1160   }
1161
1162   // remove any child track or source nodes to prevent their loading
1163   while (el.hasChildNodes()) {
1164     el.removeChild(el.firstChild);
1165   }
1166
1167   // remove any src reference. not setting `src=''` because that causes a warning
1168   // in firefox
1169   el.removeAttribute('src');
1170
1171   // force the media element to update its loading state by calling load()
1172   // however IE on Windows 7N has a bug that throws an error so need a try/catch (#793)
1173   if (typeof el.load === 'function') {
1174     // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473)
1175     (function () {
1176       try {
1177         el.load();
1178       } catch (e) {
1179         // not supported
1180       }
1181     })();
1182   }
1183 };
1184
1185 Html5.resetMediaElement = function (el) {
1186   if (!el) {
1187     return;
1188   }
1189
1190   var sources = el.querySelectorAll('source');
1191   var i = sources.length;
1192
1193   while (i--) {
1194     el.removeChild(sources[i]);
1195   }
1196
1197   // remove any src reference.
1198   // not setting `src=''` because that throws an error
1199   el.removeAttribute('src');
1200
1201   if (typeof el.load === 'function') {
1202     // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473)
1203     (function () {
1204       try {
1205         el.load();
1206       } catch (e) {
1207         // satisfy linter
1208       }
1209     })();
1210   }
1211 };
1212
1213 /* Native HTML5 element property wrapping ----------------------------------- */
1214 // Wrap native properties with a getter
1215 [
1216 /**
1217  * Get the value of `paused` from the media element. `paused` indicates whether the media element
1218  * is currently paused or not.
1219  *
1220  * @method Html5#paused
1221  * @return {boolean}
1222  *         The value of `paused` from the media element.
1223  *
1224  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-paused}
1225  */
1226 'paused',
1227
1228 /**
1229  * Get the value of `currentTime` from the media element. `currentTime` indicates
1230  * the current second that the media is at in playback.
1231  *
1232  * @method Html5#currentTime
1233  * @return {number}
1234  *         The value of `currentTime` from the media element.
1235  *
1236  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-currenttime}
1237  */
1238 'currentTime',
1239
1240 /**
1241  * Get the value of `buffered` from the media element. `buffered` is a `TimeRange`
1242  * object that represents the parts of the media that are already downloaded and
1243  * available for playback.
1244  *
1245  * @method Html5#buffered
1246  * @return {TimeRange}
1247  *         The value of `buffered` from the media element.
1248  *
1249  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-buffered}
1250  */
1251 'buffered',
1252
1253 /**
1254  * Get the value of `volume` from the media element. `volume` indicates
1255  * the current playback volume of audio for a media. `volume` will be a value from 0
1256  * (silent) to 1 (loudest and default).
1257  *
1258  * @method Html5#volume
1259  * @return {number}
1260  *         The value of `volume` from the media element. Value will be between 0-1.
1261  *
1262  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume}
1263  */
1264 'volume',
1265
1266 /**
1267  * Get the value of `muted` from the media element. `muted` indicates
1268  * that the volume for the media should be set to silent. This does not actually change
1269  * the `volume` attribute.
1270  *
1271  * @method Html5#muted
1272  * @return {boolean}
1273  *         - True if the value of `volume` should be ignored and the audio set to silent.
1274  *         - False if the value of `volume` should be used.
1275  *
1276  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted}
1277  */
1278 'muted',
1279
1280 /**
1281  * Get the value of `poster` from the media element. `poster` indicates
1282  * that the url of an image file that can/will be shown when no media data is available.
1283  *
1284  * @method Html5#poster
1285  * @return {string}
1286  *         The value of `poster` from the media element. Value will be a url to an
1287  *         image.
1288  *
1289  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-video-poster}
1290  */
1291 'poster',
1292
1293 /**
1294  * Get the value of `preload` from the media element. `preload` indicates
1295  * what should download before the media is interacted with. It can have the following
1296  * values:
1297  * - none: nothing should be downloaded
1298  * - metadata: poster and the first few frames of the media may be downloaded to get
1299  *   media dimensions and other metadata
1300  * - auto: allow the media and metadata for the media to be downloaded before
1301  *    interaction
1302  *
1303  * @method Html5#preload
1304  * @return {string}
1305  *         The value of `preload` from the media element. Will be 'none', 'metadata',
1306  *         or 'auto'.
1307  *
1308  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload}
1309  */
1310 'preload',
1311
1312 /**
1313  * Get the value of `autoplay` from the media element. `autoplay` indicates
1314  * that the media should start to play as soon as the page is ready.
1315  *
1316  * @method Html5#autoplay
1317  * @return {boolean}
1318  *         - The value of `autoplay` from the media element.
1319  *         - True indicates that the media should start as soon as the page loads.
1320  *         - False indicates that the media should not start as soon as the page loads.
1321  *
1322  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay}
1323  */
1324 'autoplay',
1325
1326 /**
1327  * Get the value of `controls` from the media element. `controls` indicates
1328  * whether the native media controls should be shown or hidden.
1329  *
1330  * @method Html5#controls
1331  * @return {boolean}
1332  *         - The value of `controls` from the media element.
1333  *         - True indicates that native controls should be showing.
1334  *         - False indicates that native controls should be hidden.
1335  *
1336  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-controls}
1337  */
1338 'controls',
1339
1340 /**
1341  * Get the value of `loop` from the media element. `loop` indicates
1342  * that the media should return to the start of the media and continue playing once
1343  * it reaches the end.
1344  *
1345  * @method Html5#loop
1346  * @return {boolean}
1347  *         - The value of `loop` from the media element.
1348  *         - True indicates that playback should seek back to start once
1349  *           the end of a media is reached.
1350  *         - False indicates that playback should not loop back to the start when the
1351  *           end of the media is reached.
1352  *
1353  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop}
1354  */
1355 'loop',
1356
1357 /**
1358  * Get the value of the `error` from the media element. `error` indicates any
1359  * MediaError that may have occured during playback. If error returns null there is no
1360  * current error.
1361  *
1362  * @method Html5#error
1363  * @return {MediaError|null}
1364  *         The value of `error` from the media element. Will be `MediaError` if there
1365  *         is a current error and null otherwise.
1366  *
1367  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-error}
1368  */
1369 'error',
1370
1371 /**
1372  * Get the value of `seeking` from the media element. `seeking` indicates whether the
1373  * media is currently seeking to a new position or not.
1374  *
1375  * @method Html5#seeking
1376  * @return {boolean}
1377  *         - The value of `seeking` from the media element.
1378  *         - True indicates that the media is currently seeking to a new position.
1379  *         - Flase indicates that the media is not seeking to a new position at this time.
1380  *
1381  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seeking}
1382  */
1383 'seeking',
1384
1385 /**
1386  * Get the value of `seekable` from the media element. `seekable` returns a
1387  * `TimeRange` object indicating ranges of time that can currently be `seeked` to.
1388  *
1389  * @method Html5#seekable
1390  * @return {TimeRange}
1391  *         The value of `seekable` from the media element. A `TimeRange` object
1392  *         indicating the current ranges of time that can be seeked to.
1393  *
1394  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seekable}
1395  */
1396 'seekable',
1397
1398 /**
1399  * Get the value of `ended` from the media element. `ended` indicates whether
1400  * the media has reached the end or not.
1401  *
1402  * @method Html5#ended
1403  * @return {boolean}
1404  *         - The value of `ended` from the media element.
1405  *         - True indicates that the media has ended.
1406  *         - False indicates that the media has not ended.
1407  *
1408  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended}
1409  */
1410 'ended',
1411
1412 /**
1413  * Get the value of `defaultMuted` from the media element. `defaultMuted` indicates
1414  * whether the media should start muted or not. Only changes the default state of the
1415  * media. `muted` and `defaultMuted` can have different values. `muted` indicates the
1416  * current state.
1417  *
1418  * @method Html5#defaultMuted
1419  * @return {boolean}
1420  *         - The value of `defaultMuted` from the media element.
1421  *         - True indicates that the media should start muted.
1422  *         - False indicates that the media should not start muted
1423  *
1424  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted}
1425  */
1426 'defaultMuted',
1427
1428 /**
1429  * Get the value of `playbackRate` from the media element. `playbackRate` indicates
1430  * the rate at which the media is currently playing back. Examples:
1431  *   - if playbackRate is set to 2, media will play twice as fast.
1432  *   - if playbackRate is set to 0.5, media will play half as fast.
1433  *
1434  * @method Html5#playbackRate
1435  * @return {number}
1436  *         The value of `playbackRate` from the media element. A number indicating
1437  *         the current playback speed of the media, where 1 is normal speed.
1438  *
1439  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}
1440  */
1441 'playbackRate',
1442
1443 /**
1444  * Get the value of `played` from the media element. `played` returns a `TimeRange`
1445  * object representing points in the media timeline that have been played.
1446  *
1447  * @method Html5#played
1448  * @return {TimeRange}
1449  *         The value of `played` from the media element. A `TimeRange` object indicating
1450  *         the ranges of time that have been played.
1451  *
1452  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-played}
1453  */
1454 'played',
1455
1456 /**
1457  * Get the value of `networkState` from the media element. `networkState` indicates
1458  * the current network state. It returns an enumeration from the following list:
1459  * - 0: NETWORK_EMPTY
1460  * - 1: NEWORK_IDLE
1461  * - 2: NETWORK_LOADING
1462  * - 3: NETWORK_NO_SOURCE
1463  *
1464  * @method Html5#networkState
1465  * @return {number}
1466  *         The value of `networkState` from the media element. This will be a number
1467  *         from the list in the description.
1468  *
1469  * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-networkstate}
1470  */
1471 'networkState',
1472
1473 /**
1474  * Get the value of `readyState` from the media element. `readyState` indicates
1475  * the current state of the media element. It returns an enumeration from the
1476  * following list:
1477  * - 0: HAVE_NOTHING
1478  * - 1: HAVE_METADATA
1479  * - 2: HAVE_CURRENT_DATA
1480  * - 3: HAVE_FUTURE_DATA
1481  * - 4: HAVE_ENOUGH_DATA
1482  *
1483  * @method Html5#readyState
1484  * @return {number}
1485  *         The value of `readyState` from the media element. This will be a number
1486  *         from the list in the description.
1487  *
1488  * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#ready-states}
1489  */
1490 'readyState',
1491
1492 /**
1493  * Get the value of `videoWidth` from the video element. `videoWidth` indicates
1494  * the current width of the video in css pixels.
1495  *
1496  * @method Html5#videoWidth
1497  * @return {number}
1498  *         The value of `videoWidth` from the video element. This will be a number
1499  *         in css pixels.
1500  *
1501  * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth}
1502  */
1503 'videoWidth',
1504
1505 /**
1506  * Get the value of `videoHeight` from the video element. `videoHeigth` indicates
1507  * the current height of the video in css pixels.
1508  *
1509  * @method Html5#videoHeight
1510  * @return {number}
1511  *         The value of `videoHeight` from the video element. This will be a number
1512  *         in css pixels.
1513  *
1514  * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth}
1515  */
1516 'videoHeight'].forEach(function (prop) {
1517   Html5.prototype[prop] = function () {
1518     return this.el_[prop];
1519   };
1520 });
1521
1522 // Wrap native properties with a setter in this format:
1523 // set + toTitleCase(name)
1524 [
1525 /**
1526  * Set the value of `volume` on the media element. `volume` indicates the current
1527  * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and
1528  * so on.
1529  *
1530  * @method Html5#setVolume
1531  * @param {number} percentAsDecimal
1532  *        The volume percent as a decimal. Valid range is from 0-1.
1533  *
1534  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume}
1535  */
1536 'volume',
1537
1538 /**
1539  * Set the value of `muted` on the media element. `muted` indicates the current
1540  * audio level should be silent.
1541  *
1542  * @method Html5#setMuted
1543  * @param {boolean} muted
1544  *        - True if the audio should be set to silent
1545  *        - False otherwise
1546  *
1547  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted}
1548  */
1549 'muted',
1550
1551 /**
1552  * Set the value of `src` on the media element. `src` indicates the current
1553  * {@link Tech~SourceObject} for the media.
1554  *
1555  * @method Html5#setSrc
1556  * @param {Tech~SourceObject} src
1557  *        The source object to set as the current source.
1558  *
1559  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-src}
1560  */
1561 'src',
1562
1563 /**
1564  * Set the value of `poster` on the media element. `poster` is the url to
1565  * an image file that can/will be shown when no media data is available.
1566  *
1567  * @method Html5#setPoster
1568  * @param {string} poster
1569  *        The url to an image that should be used as the `poster` for the media
1570  *        element.
1571  *
1572  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-poster}
1573  */
1574 'poster',
1575
1576 /**
1577  * Set the value of `preload` on the media element. `preload` indicates
1578  * what should download before the media is interacted with. It can have the following
1579  * values:
1580  * - none: nothing should be downloaded
1581  * - metadata: poster and the first few frames of the media may be downloaded to get
1582  *   media dimensions and other metadata
1583  * - auto: allow the media and metadata for the media to be downloaded before
1584  *    interaction
1585  *
1586  * @method Html5#setPreload
1587  * @param {string} preload
1588  *         The value of `preload` to set on the media element. Must be 'none', 'metadata',
1589  *         or 'auto'.
1590  *
1591  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload}
1592  */
1593 'preload',
1594
1595 /**
1596  * Set the value of `autoplay` on the media element. `autoplay` indicates
1597  * that the media should start to play as soon as the page is ready.
1598  *
1599  * @method Html5#setAutoplay
1600  * @param {boolean} autoplay
1601  *         - True indicates that the media should start as soon as the page loads.
1602  *         - False indicates that the media should not start as soon as the page loads.
1603  *
1604  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay}
1605  */
1606 'autoplay',
1607
1608 /**
1609  * Set the value of `loop` on the media element. `loop` indicates
1610  * that the media should return to the start of the media and continue playing once
1611  * it reaches the end.
1612  *
1613  * @method Html5#setLoop
1614  * @param {boolean} loop
1615  *         - True indicates that playback should seek back to start once
1616  *           the end of a media is reached.
1617  *         - False indicates that playback should not loop back to the start when the
1618  *           end of the media is reached.
1619  *
1620  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop}
1621  */
1622 'loop',
1623
1624 /**
1625  * Set the value of `playbackRate` on the media element. `playbackRate` indicates
1626  * the rate at which the media should play back. Examples:
1627  *   - if playbackRate is set to 2, media will play twice as fast.
1628  *   - if playbackRate is set to 0.5, media will play half as fast.
1629  *
1630  * @method Html5#setPlaybackRate
1631  * @return {number}
1632  *         The value of `playbackRate` from the media element. A number indicating
1633  *         the current playback speed of the media, where 1 is normal speed.
1634  *
1635  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}
1636  */
1637 'playbackRate'].forEach(function (prop) {
1638   Html5.prototype['set' + (0, _toTitleCase2['default'])(prop)] = function (v) {
1639     this.el_[prop] = v;
1640   };
1641 });
1642
1643 // wrap native functions with a function
1644 [
1645 /**
1646  * A wrapper around the media elements `pause` function. This will call the `HTML5`
1647  * media elements `pause` function.
1648  *
1649  * @method Html5#pause
1650  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-pause}
1651  */
1652 'pause',
1653
1654 /**
1655  * A wrapper around the media elements `load` function. This will call the `HTML5`s
1656  * media element `load` function.
1657  *
1658  * @method Html5#load
1659  * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-load}
1660  */
1661 'load'].forEach(function (prop) {
1662   Html5.prototype[prop] = function () {
1663     return this.el_[prop]();
1664   };
1665 });
1666
1667 _tech2['default'].withSourceHandlers(Html5);
1668
1669 /**
1670  * Native source handler for Html5, simply passes the source to the media element.
1671  *
1672  * @proprety {Tech~SourceObject} source
1673  *        The source object
1674  *
1675  * @proprety {Html5} tech
1676  *        The instance of the HTML5 tech.
1677  */
1678 Html5.nativeSourceHandler = {};
1679
1680 /**
1681  * Check if the media element can play the given mime type.
1682  *
1683  * @param {string} type
1684  *        The mimetype to check
1685  *
1686  * @return {string}
1687  *         'probably', 'maybe', or '' (empty string)
1688  */
1689 Html5.nativeSourceHandler.canPlayType = function (type) {
1690   // IE9 on Windows 7 without MediaPlayer throws an error here
1691   // https://github.com/videojs/video.js/issues/519
1692   try {
1693     return Html5.TEST_VID.canPlayType(type);
1694   } catch (e) {
1695     return '';
1696   }
1697 };
1698
1699 /**
1700  * Check if the media element can handle a source natively.
1701  *
1702  * @param {Tech~SourceObject} source
1703  *         The source object
1704  *
1705  * @param {Object} [options]
1706  *         Options to be passed to the tech.
1707  *
1708  * @return {string}
1709  *         'probably', 'maybe', or '' (empty string).
1710  */
1711 Html5.nativeSourceHandler.canHandleSource = function (source, options) {
1712
1713   // If a type was provided we should rely on that
1714   if (source.type) {
1715     return Html5.nativeSourceHandler.canPlayType(source.type);
1716
1717     // If no type, fall back to checking 'video/[EXTENSION]'
1718   } else if (source.src) {
1719     var ext = Url.getFileExtension(source.src);
1720
1721     return Html5.nativeSourceHandler.canPlayType('video/' + ext);
1722   }
1723
1724   return '';
1725 };
1726
1727 /**
1728  * Pass the source to the native media element.
1729  *
1730  * @param {Tech~SourceObject} source
1731  *        The source object
1732  *
1733  * @param {Html5} tech
1734  *        The instance of the Html5 tech
1735  *
1736  * @param {Object} [options]
1737  *        The options to pass to the source
1738  */
1739 Html5.nativeSourceHandler.handleSource = function (source, tech, options) {
1740   tech.setSrc(source.src);
1741 };
1742
1743 /**
1744  * A noop for the native dispose function, as cleanup is not needed.
1745  */
1746 Html5.nativeSourceHandler.dispose = function () {};
1747
1748 // Register the native source handler
1749 Html5.registerSourceHandler(Html5.nativeSourceHandler);
1750
1751 _component2['default'].registerComponent('Html5', Html5);
1752 _tech2['default'].registerTech('Html5', Html5);
1753 exports['default'] = Html5;