3 exports.__esModule = true;
5 var _component = require('../component');
7 var _component2 = _interopRequireDefault(_component);
9 var _htmlTrackElement = require('../tracks/html-track-element');
11 var _htmlTrackElement2 = _interopRequireDefault(_htmlTrackElement);
13 var _htmlTrackElementList = require('../tracks/html-track-element-list');
15 var _htmlTrackElementList2 = _interopRequireDefault(_htmlTrackElementList);
17 var _mergeOptions = require('../utils/merge-options.js');
19 var _mergeOptions2 = _interopRequireDefault(_mergeOptions);
21 var _textTrack = require('../tracks/text-track');
23 var _textTrack2 = _interopRequireDefault(_textTrack);
25 var _textTrackList = require('../tracks/text-track-list');
27 var _textTrackList2 = _interopRequireDefault(_textTrackList);
29 var _videoTrackList = require('../tracks/video-track-list');
31 var _videoTrackList2 = _interopRequireDefault(_videoTrackList);
33 var _audioTrackList = require('../tracks/audio-track-list');
35 var _audioTrackList2 = _interopRequireDefault(_audioTrackList);
37 var _fn = require('../utils/fn.js');
39 var Fn = _interopRequireWildcard(_fn);
41 var _log = require('../utils/log.js');
43 var _log2 = _interopRequireDefault(_log);
45 var _timeRanges = require('../utils/time-ranges.js');
47 var _buffer = require('../utils/buffer.js');
49 var _mediaError = require('../media-error.js');
51 var _mediaError2 = _interopRequireDefault(_mediaError);
53 var _window = require('global/window');
55 var _window2 = _interopRequireDefault(_window);
57 var _document = require('global/document');
59 var _document2 = _interopRequireDefault(_document);
61 var _obj = require('../utils/obj');
63 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; } }
65 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
67 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
69 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; }
71 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; } /**
76 * An Object containing a structure like: `{src: 'url', type: 'mimetype'}` or string
77 * that just contains the src url alone.
78 * * `var SourceObject = {src: 'http://ex.com/video.mp4', type: 'video/mp4'};`
79 * `var SourceString = 'http://example.com/some-video.mp4';`
81 * @typedef {Object|string} Tech~SourceObject
83 * @property {string} src
84 * The url to the source
86 * @property {string} type
87 * The mime type of the source
91 * A function used by {@link Tech} to create a new {@link TextTrack}.
94 * An instance of the Tech class.
96 * @param {string} kind
97 * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)
99 * @param {string} [label]
100 * Label to identify the text track
102 * @param {string} [language]
103 * Two letter language abbreviation
105 * @param {Object} [options={}]
106 * An object with additional text track options
108 * @return {TextTrack}
109 * The text track that was created.
111 function createTrackHelper(self, kind, label, language) {
112 var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
114 var tracks = self.textTracks();
119 options.label = label;
122 options.language = language;
126 var track = new _textTrack2['default'](options);
128 tracks.addTrack_(track);
134 * This is the base class for media playback technology controllers, such as
135 * {@link Flash} and {@link HTML5}
140 var Tech = function (_Component) {
141 _inherits(Tech, _Component);
144 * Create an instance of this Tech.
146 * @param {Object} [options]
147 * The key/value store of player options.
149 * @param {Component~ReadyCallback} ready
150 * Callback function to call when the `HTML5` Tech is ready.
153 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
154 var ready = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
156 _classCallCheck(this, Tech);
158 // we don't want the tech to report user activity automatically.
159 // This is done manually in addControlsListeners
160 options.reportTouchActivity = false;
162 // keep track of whether the current source has played at all to
163 // implement a very limited played()
164 var _this = _possibleConstructorReturn(this, _Component.call(this, null, options, ready));
166 _this.hasStarted_ = false;
167 _this.on('playing', function () {
168 this.hasStarted_ = true;
170 _this.on('loadstart', function () {
171 this.hasStarted_ = false;
174 _this.textTracks_ = options.textTracks;
175 _this.videoTracks_ = options.videoTracks;
176 _this.audioTracks_ = options.audioTracks;
178 // Manually track progress in cases where the browser/flash player doesn't report it.
179 if (!_this.featuresProgressEvents) {
180 _this.manualProgressOn();
183 // Manually track timeupdates in cases where the browser/flash player doesn't report it.
184 if (!_this.featuresTimeupdateEvents) {
185 _this.manualTimeUpdatesOn();
188 ['Text', 'Audio', 'Video'].forEach(function (track) {
189 if (options['native' + track + 'Tracks'] === false) {
190 _this['featuresNative' + track + 'Tracks'] = false;
194 if (options.nativeCaptions === false) {
195 _this.featuresNativeTextTracks = false;
198 if (!_this.featuresNativeTextTracks) {
199 _this.emulateTextTracks();
202 _this.autoRemoteTextTracks_ = new _textTrackList2['default']();
204 _this.initTextTrackListeners();
205 _this.initTrackListeners();
207 // Turn on component tap events only if not using native controls
208 if (!options.nativeControlsForTouch) {
209 _this.emitTapEvents();
212 if (_this.constructor) {
213 _this.name_ = _this.constructor.name || 'Unknown Tech';
218 /* Fallbacks for unsupported event types
219 ================================================================================ */
222 * Polyfill the `progress` event for browsers that don't support it natively.
224 * @see {@link Tech#trackProgress}
228 Tech.prototype.manualProgressOn = function manualProgressOn() {
229 this.on('durationchange', this.onDurationChange);
231 this.manualProgress = true;
233 // Trigger progress watching when a source begins loading
234 this.one('ready', this.trackProgress);
238 * Turn off the polyfill for `progress` events that was created in
239 * {@link Tech#manualProgressOn}
243 Tech.prototype.manualProgressOff = function manualProgressOff() {
244 this.manualProgress = false;
245 this.stopTrackingProgress();
247 this.off('durationchange', this.onDurationChange);
251 * This is used to trigger a `progress` event when the buffered percent changes. It
252 * sets an interval function that will be called every 500 milliseconds to check if the
253 * buffer end percent has changed.
255 * > This function is called by {@link Tech#manualProgressOn}
257 * @param {EventTarget~Event} event
258 * The `ready` event that caused this to run.
260 * @listens Tech#ready
261 * @fires Tech#progress
265 Tech.prototype.trackProgress = function trackProgress(event) {
266 this.stopTrackingProgress();
267 this.progressInterval = this.setInterval(Fn.bind(this, function () {
268 // Don't trigger unless buffered amount is greater than last time
270 var numBufferedPercent = this.bufferedPercent();
272 if (this.bufferedPercent_ !== numBufferedPercent) {
274 * See {@link Player#progress}
276 * @event Tech#progress
277 * @type {EventTarget~Event}
279 this.trigger('progress');
282 this.bufferedPercent_ = numBufferedPercent;
284 if (numBufferedPercent === 1) {
285 this.stopTrackingProgress();
291 * Update our internal duration on a `durationchange` event by calling
292 * {@link Tech#duration}.
294 * @param {EventTarget~Event} event
295 * The `durationchange` event that caused this to run.
297 * @listens Tech#durationchange
301 Tech.prototype.onDurationChange = function onDurationChange(event) {
302 this.duration_ = this.duration();
306 * Get and create a `TimeRange` object for buffering.
308 * @return {TimeRange}
309 * The time range object that was created.
313 Tech.prototype.buffered = function buffered() {
314 return (0, _timeRanges.createTimeRange)(0, 0);
318 * Get the percentage of the current video that is currently buffered.
321 * A number from 0 to 1 that represents the decimal percentage of the
322 * video that is buffered.
327 Tech.prototype.bufferedPercent = function bufferedPercent() {
328 return (0, _buffer.bufferedPercent)(this.buffered(), this.duration_);
332 * Turn off the polyfill for `progress` events that was created in
333 * {@link Tech#manualProgressOn}
334 * Stop manually tracking progress events by clearing the interval that was set in
335 * {@link Tech#trackProgress}.
339 Tech.prototype.stopTrackingProgress = function stopTrackingProgress() {
340 this.clearInterval(this.progressInterval);
344 * Polyfill the `timeupdate` event for browsers that don't support it.
346 * @see {@link Tech#trackCurrentTime}
350 Tech.prototype.manualTimeUpdatesOn = function manualTimeUpdatesOn() {
351 this.manualTimeUpdates = true;
353 this.on('play', this.trackCurrentTime);
354 this.on('pause', this.stopTrackingCurrentTime);
358 * Turn off the polyfill for `timeupdate` events that was created in
359 * {@link Tech#manualTimeUpdatesOn}
363 Tech.prototype.manualTimeUpdatesOff = function manualTimeUpdatesOff() {
364 this.manualTimeUpdates = false;
365 this.stopTrackingCurrentTime();
366 this.off('play', this.trackCurrentTime);
367 this.off('pause', this.stopTrackingCurrentTime);
371 * Sets up an interval function to track current time and trigger `timeupdate` every
375 * @triggers Tech#timeupdate
379 Tech.prototype.trackCurrentTime = function trackCurrentTime() {
380 if (this.currentTimeInterval) {
381 this.stopTrackingCurrentTime();
383 this.currentTimeInterval = this.setInterval(function () {
385 * Triggered at an interval of 250ms to indicated that time is passing in the video.
387 * @event Tech#timeupdate
388 * @type {EventTarget~Event}
390 this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
392 // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
397 * Stop the interval function created in {@link Tech#trackCurrentTime} so that the
398 * `timeupdate` event is no longer triggered.
400 * @listens {Tech#pause}
404 Tech.prototype.stopTrackingCurrentTime = function stopTrackingCurrentTime() {
405 this.clearInterval(this.currentTimeInterval);
407 // #1002 - if the video ends right before the next timeupdate would happen,
408 // the progress bar won't make it all the way to the end
409 this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
413 * Turn off all event polyfills, clear the `Tech`s {@link AudioTrackList},
414 * {@link VideoTrackList}, and {@link TextTrackList}, and dispose of this Tech.
416 * @fires Component#dispose
420 Tech.prototype.dispose = function dispose() {
422 // clear out all tracks because we can't reuse them between techs
423 this.clearTracks(['audio', 'video', 'text']);
425 // Turn off any manual progress or timeupdate tracking
426 if (this.manualProgress) {
427 this.manualProgressOff();
430 if (this.manualTimeUpdates) {
431 this.manualTimeUpdatesOff();
434 _Component.prototype.dispose.call(this);
438 * Clear out a single `TrackList` or an array of `TrackLists` given their names.
440 * > Note: Techs without source handlers should call this between sources for `video`
441 * & `audio` tracks. You don't want to use them between tracks!
443 * @param {string[]|string} types
444 * TrackList names to clear, valid names are `video`, `audio`, and
449 Tech.prototype.clearTracks = function clearTracks(types) {
452 types = [].concat(types);
453 // clear out all tracks because we can't reuse them between techs
454 types.forEach(function (type) {
455 var list = _this2[type + 'Tracks']() || [];
461 if (type === 'text') {
462 _this2.removeRemoteTextTrack(track);
464 list.removeTrack_(track);
470 * Remove any TextTracks added via addRemoteTextTrack that are
471 * flagged for automatic garbage collection
475 Tech.prototype.cleanupAutoTextTracks = function cleanupAutoTextTracks() {
476 var list = this.autoRemoteTextTracks_ || [];
482 this.removeRemoteTextTrack(track);
487 * Reset the tech, which will removes all sources and reset the internal readyState.
493 Tech.prototype.reset = function reset() {};
496 * Get or set an error on the Tech.
498 * @param {MediaError} [err]
499 * Error to set on the Tech
501 * @return {MediaError|null}
502 * The current error object on the tech, or null if there isn't one.
506 Tech.prototype.error = function error(err) {
507 if (err !== undefined) {
508 this.error_ = new _mediaError2['default'](err);
509 this.trigger('error');
515 * Returns the `TimeRange`s that have been played through for the current source.
517 * > NOTE: This implementation is incomplete. It does not track the played `TimeRange`.
518 * It only checks wether the source has played at all or not.
520 * @return {TimeRange}
521 * - A single time range if this video has played
522 * - An empty set of ranges if not.
526 Tech.prototype.played = function played() {
527 if (this.hasStarted_) {
528 return (0, _timeRanges.createTimeRange)(0, 0);
530 return (0, _timeRanges.createTimeRange)();
534 * Causes a manual time update to occur if {@link Tech#manualTimeUpdatesOn} was
537 * @fires Tech#timeupdate
541 Tech.prototype.setCurrentTime = function setCurrentTime() {
542 // improve the accuracy of manual timeupdates
543 if (this.manualTimeUpdates) {
545 * A manual `timeupdate` event.
547 * @event Tech#timeupdate
548 * @type {EventTarget~Event}
550 this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
555 * Turn on listeners for {@link TextTrackList} events. This adds
556 * {@link EventTarget~EventListeners} for `texttrackchange`, `addtrack` and
559 * @fires Tech#texttrackchange
563 Tech.prototype.initTextTrackListeners = function initTextTrackListeners() {
564 var textTrackListChanges = Fn.bind(this, function () {
566 * Triggered when tracks are added or removed on the Tech {@link TextTrackList}
568 * @event Tech#texttrackchange
569 * @type {EventTarget~Event}
571 this.trigger('texttrackchange');
574 var tracks = this.textTracks();
580 tracks.addEventListener('removetrack', textTrackListChanges);
581 tracks.addEventListener('addtrack', textTrackListChanges);
583 this.on('dispose', Fn.bind(this, function () {
584 tracks.removeEventListener('removetrack', textTrackListChanges);
585 tracks.removeEventListener('addtrack', textTrackListChanges);
590 * Turn on listeners for {@link VideoTrackList} and {@link {AudioTrackList} events.
591 * This adds {@link EventTarget~EventListeners} for `addtrack`, and `removetrack`.
593 * @fires Tech#audiotrackchange
594 * @fires Tech#videotrackchange
598 Tech.prototype.initTrackListeners = function initTrackListeners() {
601 var trackTypes = ['video', 'audio'];
603 trackTypes.forEach(function (type) {
605 * Triggered when tracks are added or removed on the Tech {@link AudioTrackList}
607 * @event Tech#audiotrackchange
608 * @type {EventTarget~Event}
612 * Triggered when tracks are added or removed on the Tech {@link VideoTrackList}
614 * @event Tech#videotrackchange
615 * @type {EventTarget~Event}
617 var trackListChanges = function trackListChanges() {
618 _this3.trigger(type + 'trackchange');
621 var tracks = _this3[type + 'Tracks']();
623 tracks.addEventListener('removetrack', trackListChanges);
624 tracks.addEventListener('addtrack', trackListChanges);
626 _this3.on('dispose', function () {
627 tracks.removeEventListener('removetrack', trackListChanges);
628 tracks.removeEventListener('addtrack', trackListChanges);
634 * Emulate TextTracks using vtt.js if necessary
636 * @fires Tech#vttjsloaded
637 * @fires Tech#vttjserror
641 Tech.prototype.addWebVttScript_ = function addWebVttScript_() {
644 if (_window2['default'].WebVTT) {
648 // Initially, Tech.el_ is a child of a dummy-div wait until the Component system
649 // signals that the Tech is ready at which point Tech.el_ is part of the DOM
650 // before inserting the WebVTT script
651 if (_document2['default'].body.contains(this.el())) {
652 var vtt = require('videojs-vtt.js');
654 // load via require if available and vtt.js script location was not passed in
655 // as an option. novtt builds will turn the above require call into an empty object
656 // which will cause this if check to always fail.
657 if (!this.options_['vtt.js'] && (0, _obj.isPlain)(vtt) && Object.keys(vtt).length > 0) {
658 this.trigger('vttjsloaded');
662 // load vtt.js via the script location option or the cdn of no location was
664 var script = _document2['default'].createElement('script');
666 script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.12.3/vtt.min.js';
667 script.onload = function () {
669 * Fired when vtt.js is loaded.
671 * @event Tech#vttjsloaded
672 * @type {EventTarget~Event}
674 _this4.trigger('vttjsloaded');
676 script.onerror = function () {
678 * Fired when vtt.js was not loaded due to an error
680 * @event Tech#vttjsloaded
681 * @type {EventTarget~Event}
683 _this4.trigger('vttjserror');
685 this.on('dispose', function () {
686 script.onload = null;
687 script.onerror = null;
689 // but have not loaded yet and we set it to true before the inject so that
690 // we don't overwrite the injected window.WebVTT if it loads right away
691 _window2['default'].WebVTT = true;
692 this.el().parentNode.appendChild(script);
694 this.ready(this.addWebVttScript_);
701 * @method emulateTextTracks
705 Tech.prototype.emulateTextTracks = function emulateTextTracks() {
708 var tracks = this.textTracks();
714 var remoteTracks = this.remoteTextTracks();
715 var handleAddTrack = function handleAddTrack(e) {
716 return tracks.addTrack_(e.track);
718 var handleRemoveTrack = function handleRemoveTrack(e) {
719 return tracks.removeTrack_(e.track);
722 remoteTracks.on('addtrack', handleAddTrack);
723 remoteTracks.on('removetrack', handleRemoveTrack);
725 this.addWebVttScript_();
727 var updateDisplay = function updateDisplay() {
728 return _this5.trigger('texttrackchange');
731 var textTracksChanges = function textTracksChanges() {
734 for (var i = 0; i < tracks.length; i++) {
735 var track = tracks[i];
737 track.removeEventListener('cuechange', updateDisplay);
738 if (track.mode === 'showing') {
739 track.addEventListener('cuechange', updateDisplay);
745 tracks.addEventListener('change', textTracksChanges);
746 tracks.addEventListener('addtrack', textTracksChanges);
747 tracks.addEventListener('removetrack', textTracksChanges);
749 this.on('dispose', function () {
750 remoteTracks.off('addtrack', handleAddTrack);
751 remoteTracks.off('removetrack', handleRemoveTrack);
752 tracks.removeEventListener('change', textTracksChanges);
753 tracks.removeEventListener('addtrack', textTracksChanges);
754 tracks.removeEventListener('removetrack', textTracksChanges);
756 for (var i = 0; i < tracks.length; i++) {
757 var track = tracks[i];
759 track.removeEventListener('cuechange', updateDisplay);
765 * Get the `Tech`s {@link VideoTrackList}.
767 * @return {VideoTrackList}
768 * The video track list that the Tech is currently using.
772 Tech.prototype.videoTracks = function videoTracks() {
773 this.videoTracks_ = this.videoTracks_ || new _videoTrackList2['default']();
774 return this.videoTracks_;
778 * Get the `Tech`s {@link AudioTrackList}.
780 * @return {AudioTrackList}
781 * The audio track list that the Tech is currently using.
785 Tech.prototype.audioTracks = function audioTracks() {
786 this.audioTracks_ = this.audioTracks_ || new _audioTrackList2['default']();
787 return this.audioTracks_;
791 * Get the `Tech`s {@link TextTrackList}.
793 * @return {TextTrackList}
794 * The text track list that the Tech is currently using.
798 Tech.prototype.textTracks = function textTracks() {
799 this.textTracks_ = this.textTracks_ || new _textTrackList2['default']();
800 return this.textTracks_;
804 * Get the `Tech`s remote {@link TextTrackList}, which is created from elements
805 * that were added to the DOM.
807 * @return {TextTrackList}
808 * The remote text track list that the Tech is currently using.
812 Tech.prototype.remoteTextTracks = function remoteTextTracks() {
813 this.remoteTextTracks_ = this.remoteTextTracks_ || new _textTrackList2['default']();
814 return this.remoteTextTracks_;
818 * Get The `Tech`s {HTMLTrackElementList}, which are the elements in the DOM that are
819 * being used as TextTracks.
821 * @return {HTMLTrackElementList}
822 * The current HTML track elements that exist for the tech.
826 Tech.prototype.remoteTextTrackEls = function remoteTextTrackEls() {
827 this.remoteTextTrackEls_ = this.remoteTextTrackEls_ || new _htmlTrackElementList2['default']();
828 return this.remoteTextTrackEls_;
832 * Create and returns a remote {@link TextTrack} object.
834 * @param {string} kind
835 * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)
837 * @param {string} [label]
838 * Label to identify the text track
840 * @param {string} [language]
841 * Two letter language abbreviation
843 * @return {TextTrack}
844 * The TextTrack that gets created.
848 Tech.prototype.addTextTrack = function addTextTrack(kind, label, language) {
850 throw new Error('TextTrack kind is required but was not provided');
853 return createTrackHelper(this, kind, label, language);
857 * Create an emulated TextTrack for use by addRemoteTextTrack
859 * This is intended to be overridden by classes that inherit from
860 * Tech in order to create native or custom TextTracks.
862 * @param {Object} options
863 * The object should contain the options to initialize the TextTrack with.
865 * @param {string} [options.kind]
866 * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata).
868 * @param {string} [options.label].
869 * Label to identify the text track
871 * @param {string} [options.language]
872 * Two letter language abbreviation.
874 * @return {HTMLTrackElement}
875 * The track element that gets created.
879 Tech.prototype.createRemoteTextTrack = function createRemoteTextTrack(options) {
880 var track = (0, _mergeOptions2['default'])(options, {
884 return new _htmlTrackElement2['default'](track);
888 * Creates a remote text track object and returns an html track element.
890 * > Note: This can be an emulated {@link HTMLTrackElement} or a native one.
892 * @param {Object} options
893 * See {@link Tech#createRemoteTextTrack} for more detailed properties.
895 * @param {boolean} [manualCleanup=true]
896 * - When false: the TextTrack will be automatically removed from the video
897 * element whenever the source changes
898 * - When True: The TextTrack will have to be cleaned up manually
900 * @return {HTMLTrackElement}
901 * An Html Track Element.
903 * @deprecated The default functionality for this function will be equivalent
904 * to "manualCleanup=false" in the future. The manualCleanup parameter will
909 Tech.prototype.addRemoteTextTrack = function addRemoteTextTrack() {
910 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
911 var manualCleanup = arguments[1];
913 var htmlTrackElement = this.createRemoteTextTrack(options);
915 if (manualCleanup !== true && manualCleanup !== false) {
916 // deprecation warning
917 _log2['default'].warn('Calling addRemoteTextTrack without explicitly setting the "manualCleanup" parameter to `true` is deprecated and default to `false` in future version of video.js');
918 manualCleanup = true;
921 // store HTMLTrackElement and TextTrack to remote list
922 this.remoteTextTrackEls().addTrackElement_(htmlTrackElement);
923 this.remoteTextTracks().addTrack_(htmlTrackElement.track);
925 if (manualCleanup !== true) {
926 // create the TextTrackList if it doesn't exist
927 this.autoRemoteTextTracks_.addTrack_(htmlTrackElement.track);
930 return htmlTrackElement;
934 * Remove a remote text track from the remote `TextTrackList`.
936 * @param {TextTrack} track
937 * `TextTrack` to remove from the `TextTrackList`
941 Tech.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) {
942 var trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track);
944 // remove HTMLTrackElement and TextTrack from remote list
945 this.remoteTextTrackEls().removeTrackElement_(trackElement);
946 this.remoteTextTracks().removeTrack_(track);
947 this.autoRemoteTextTracks_.removeTrack_(track);
951 * A method to set a poster from a `Tech`.
957 Tech.prototype.setPoster = function setPoster() {};
960 * Check if the tech can support the given mime-type.
962 * The base tech does not support any type, but source handlers might
965 * @param {string} type
966 * The mimetype to check for support
969 * 'probably', 'maybe', or empty string
971 * @see [Spec]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType}
977 Tech.prototype.canPlayType = function canPlayType() {
982 * Return whether the argument is a Tech or not.
983 * Can be passed either a Class like `Html5` or a instance like `player.tech_`
985 * @param {Object} component
989 * Whether it is a tech or not
990 * - True if it is a tech
991 * - False if it is not
995 Tech.isTech = function isTech(component) {
996 return component.prototype instanceof Tech || component instanceof Tech || component === Tech;
1000 * Registers a `Tech` into a shared list for videojs.
1002 * @param {string} name
1003 * Name of the `Tech` to register.
1005 * @param {Object} tech
1006 * The `Tech` class to register.
1010 Tech.registerTech = function registerTech(name, tech) {
1015 if (!Tech.isTech(tech)) {
1016 throw new Error('Tech ' + name + ' must be a Tech');
1019 Tech.techs_[name] = tech;
1024 * Get a `Tech` from the shared list by name.
1026 * @param {string} name
1027 * Name of the component to get
1029 * @return {Tech|undefined}
1030 * The `Tech` or undefined if there was no tech with the name requsted.
1034 Tech.getTech = function getTech(name) {
1035 if (Tech.techs_ && Tech.techs_[name]) {
1036 return Tech.techs_[name];
1039 if (_window2['default'] && _window2['default'].videojs && _window2['default'].videojs[name]) {
1040 _log2['default'].warn('The ' + name + ' tech was added to the videojs object when it should be registered using videojs.registerTech(name, tech)');
1041 return _window2['default'].videojs[name];
1046 }(_component2['default']);
1049 * List of associated text tracks.
1051 * @type {TextTrackList}
1056 Tech.prototype.textTracks_; // eslint-disable-line
1059 * List of associated audio tracks.
1061 * @type {AudioTrackList}
1064 Tech.prototype.audioTracks_; // eslint-disable-line
1067 * List of associated video tracks.
1069 * @type {VideoTrackList}
1072 Tech.prototype.videoTracks_; // eslint-disable-line
1075 * Boolean indicating wether the `Tech` supports volume control.
1080 Tech.prototype.featuresVolumeControl = true;
1083 * Boolean indicating wether the `Tech` support fullscreen resize control.
1084 * Resizing plugins using request fullscreen reloads the plugin
1089 Tech.prototype.featuresFullscreenResize = false;
1092 * Boolean indicating wether the `Tech` supports changing the speed at which the video
1094 * - Set player to play 2x (twice) as fast
1095 * - Set player to play 0.5x (half) as fast
1100 Tech.prototype.featuresPlaybackRate = false;
1103 * Boolean indicating wether the `Tech` supports the `progress` event. This is currently
1104 * not triggered by video-js-swf. This will be used to determine if
1105 * {@link Tech#manualProgressOn} should be called.
1110 Tech.prototype.featuresProgressEvents = false;
1113 * Boolean indicating wether the `Tech` supports the `timeupdate` event. This is currently
1114 * not triggered by video-js-swf. This will be used to determine if
1115 * {@link Tech#manualTimeUpdates} should be called.
1120 Tech.prototype.featuresTimeupdateEvents = false;
1123 * Boolean indicating wether the `Tech` supports the native `TextTrack`s.
1124 * This will help us integrate with native `TextTrack`s if the browser supports them.
1129 Tech.prototype.featuresNativeTextTracks = false;
1132 * A functional mixin for techs that want to use the Source Handler pattern.
1133 * Source handlers are scripts for handling specific formats.
1134 * The source handler pattern is used for adaptive formats (HLS, DASH) that
1135 * manually load video data and feed it into a Source Buffer (Media Source Extensions)
1136 * Example: `Tech.withSourceHandlers.call(MyTech);`
1138 * @param {Tech} _Tech
1139 * The tech to add source handler functions to.
1141 * @mixes Tech~SourceHandlerAdditions
1143 Tech.withSourceHandlers = function (_Tech) {
1146 * Register a source handler
1148 * @param {Function} handler
1149 * The source handler class
1151 * @param {number} [index]
1152 * Register it at the following index
1154 _Tech.registerSourceHandler = function (handler, index) {
1155 var handlers = _Tech.sourceHandlers;
1158 handlers = _Tech.sourceHandlers = [];
1161 if (index === undefined) {
1162 // add to the end of the list
1163 index = handlers.length;
1166 handlers.splice(index, 0, handler);
1170 * Check if the tech can support the given type. Also checks the
1171 * Techs sourceHandlers.
1173 * @param {string} type
1174 * The mimetype to check.
1177 * 'probably', 'maybe', or '' (empty string)
1179 _Tech.canPlayType = function (type) {
1180 var handlers = _Tech.sourceHandlers || [];
1183 for (var i = 0; i < handlers.length; i++) {
1184 can = handlers[i].canPlayType(type);
1195 * Returns the first source handler that supports the source.
1197 * TODO: Answer question: should 'probably' be prioritized over 'maybe'
1199 * @param {Tech~SourceObject} source
1202 * @param {Object} options
1203 * The options passed to the tech
1205 * @return {SourceHandler|null}
1206 * The first source handler that supports the source or null if
1207 * no SourceHandler supports the source
1209 _Tech.selectSourceHandler = function (source, options) {
1210 var handlers = _Tech.sourceHandlers || [];
1213 for (var i = 0; i < handlers.length; i++) {
1214 can = handlers[i].canHandleSource(source, options);
1225 * Check if the tech can support the given source.
1227 * @param {Tech~SourceObject} srcObj
1230 * @param {Object} options
1231 * The options passed to the tech
1234 * 'probably', 'maybe', or '' (empty string)
1236 _Tech.canPlaySource = function (srcObj, options) {
1237 var sh = _Tech.selectSourceHandler(srcObj, options);
1240 return sh.canHandleSource(srcObj, options);
1247 * When using a source handler, prefer its implementation of
1248 * any function normally provided by the tech.
1250 var deferrable = ['seekable', 'duration'];
1253 * A wrapper around {@link Tech#seekable} that will call a `SourceHandler`s seekable
1254 * function if it exists, with a fallback to the Techs seekable function.
1256 * @method _Tech.seekable
1260 * A wrapper around {@link Tech#duration} that will call a `SourceHandler`s duration
1261 * function if it exists, otherwise it will fallback to the techs duration function.
1263 * @method _Tech.duration
1266 deferrable.forEach(function (fnName) {
1267 var originalFn = this[fnName];
1269 if (typeof originalFn !== 'function') {
1273 this[fnName] = function () {
1274 if (this.sourceHandler_ && this.sourceHandler_[fnName]) {
1275 return this.sourceHandler_[fnName].apply(this.sourceHandler_, arguments);
1277 return originalFn.apply(this, arguments);
1279 }, _Tech.prototype);
1282 * Create a function for setting the source using a source object
1283 * and source handlers.
1284 * Should never be called unless a source handler was found.
1286 * @param {Tech~SourceObject} source
1287 * A source object with src and type keys
1290 * Returns itself; this method is chainable
1292 _Tech.prototype.setSource = function (source) {
1293 var sh = _Tech.selectSourceHandler(source, this.options_);
1296 // Fall back to a native source hander when unsupported sources are
1298 if (_Tech.nativeSourceHandler) {
1299 sh = _Tech.nativeSourceHandler;
1301 _log2['default'].error('No source hander found for the current source.');
1305 // Dispose any existing source handler
1306 this.disposeSourceHandler();
1307 this.off('dispose', this.disposeSourceHandler);
1309 if (sh !== _Tech.nativeSourceHandler) {
1310 this.currentSource_ = source;
1312 // Catch if someone replaced the src without calling setSource.
1313 // If they do, set currentSource_ to null and dispose our source handler.
1314 this.off(this.el_, 'loadstart', _Tech.prototype.firstLoadStartListener_);
1315 this.off(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_);
1316 this.one(this.el_, 'loadstart', _Tech.prototype.firstLoadStartListener_);
1319 this.sourceHandler_ = sh.handleSource(source, this, this.options_);
1320 this.on('dispose', this.disposeSourceHandler);
1326 * Called once for the first loadstart of a video.
1328 * @listens Tech#loadstart
1330 _Tech.prototype.firstLoadStartListener_ = function () {
1331 this.one(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_);
1334 // On successive loadstarts when setSource has not been called again
1336 * Called after the first loadstart for a video occurs.
1338 * @listens Tech#loadstart
1340 _Tech.prototype.successiveLoadStartListener_ = function () {
1341 this.disposeSourceHandler();
1342 this.one(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_);
1346 * Clean up any existing SourceHandlers and listeners when the Tech is disposed.
1348 * @listens Tech#dispose
1350 _Tech.prototype.disposeSourceHandler = function () {
1351 // if we have a source and get another one
1352 // then we are loading something new
1353 // than clear all of our current tracks
1354 if (this.currentSource_) {
1355 this.clearTracks(['audio', 'video']);
1356 this.currentSource_ = null;
1359 // always clean up auto-text tracks
1360 this.cleanupAutoTextTracks();
1362 if (this.sourceHandler_) {
1363 this.off(this.el_, 'loadstart', _Tech.prototype.firstLoadStartListener_);
1364 this.off(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_);
1366 if (this.sourceHandler_.dispose) {
1367 this.sourceHandler_.dispose();
1370 this.sourceHandler_ = null;
1375 _component2['default'].registerComponent('Tech', Tech);
1376 // Old name for Tech
1378 _component2['default'].registerComponent('MediaTechController', Tech);
1379 Tech.registerTech('Tech', Tech);
1380 exports['default'] = Tech;