Bump video.js to v7.20.1
authorOmar Sweidan <omar.sweidan@userrendszerhaz.hu>
Fri, 29 Jul 2022 11:12:51 +0000 (13:12 +0200)
committerOmar Sweidan <omar.sweidan@userrendszerhaz.hu>
Fri, 29 Jul 2022 11:12:51 +0000 (13:12 +0200)
server/user.mediacube.gui/js/video.js

index 5151e7e42f2e311118cb7ced4f1e73a4ae2eb6ee..c33b83475ac52dc302e8c7263177fb227bd2e53e 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * @license
- * Video.js 7.18.1 <http://videojs.com/>
+ * Video.js 7.20.1 <http://videojs.com/>
  * Copyright Brightcove, Inc. <https://www.brightcove.com/>
  * Available under Apache License Version 2.0
  * <https://github.com/videojs/video.js/blob/main/LICENSE>
@@ -16,7 +16,7 @@
   (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.videojs = factory());
 }(this, (function () { 'use strict';
 
-  var version$5 = "7.18.1";
+  var version$5 = "7.20.1";
 
   /**
    * An Object that contains lifecycle hooks as keys which point to an array
         // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y
         // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation
         // and webkitMovementX/Y
-        if (key !== 'layerX' && key !== 'layerY' && key !== 'keyLocation' && key !== 'webkitMovementX' && key !== 'webkitMovementY') {
+        // Lighthouse complains if Event.path is copied
+        if (key !== 'layerX' && key !== 'layerY' && key !== 'keyLocation' && key !== 'webkitMovementX' && key !== 'webkitMovementY' && key !== 'path') {
           // Chrome 32+ warns if you try to copy deprecated returnValue, but
           // we still want to if preventDefault isn't supported (IE8).
           if (!(key === 'returnValue' && old.preventDefault)) {
     return SetSham;
   }();
 
-  var Set = window.Set ? window.Set : SetSham;
+  var Set$1 = window.Set ? window.Set : SetSham;
 
   var keycode = createCommonjsModule(function (module, exports) {
     // Source: http://jsfiddle.net/vWx8V/
      *        The `Player` that this class should be attached to.
      *
      * @param {Object} [options]
-     *        The key/value store of player options.
+     *        The key/value store of component options.
      *
      * @param {Object[]} [options.children]
      *        An array of children objects to intialize this component with. Children objects have
      *        a name property that will be used if more than one component of the same type needs to be
      *        added.
      *
+     * @param  {string} [options.className]
+     *         A class or space separated list of classes to add the component
+     *
      * @param {Component~ReadyCallback} [ready]
      *        Function that gets called when the `Component` is ready.
      */
     function Component(player, options, ready) {
+      var _this = this;
+
       // The component might be the player itself and we can't pass `this` to super
       if (!player && this.play) {
         this.player_ = player = this; // eslint-disable-line
         this.el_ = options.el;
       } else if (options.createEl !== false) {
         this.el_ = this.createEl();
+      }
+
+      if (options.className && this.el_) {
+        options.className.split(' ').forEach(function (c) {
+          return _this.addClass(c);
+        });
       } // if evented is anything except false, we want to mixin in evented
 
 
       this.children_ = [];
       this.childIndex_ = {};
       this.childNameIndex_ = {};
-      this.setTimeoutIds_ = new Set();
-      this.setIntervalIds_ = new Set();
-      this.rafIds_ = new Set();
+      this.setTimeoutIds_ = new Set$1();
+      this.setIntervalIds_ = new Set$1();
+      this.rafIds_ = new Set$1();
       this.namedRafs_ = new Map$1();
       this.clearingTimersOnDispose_ = false; // Add any child components in options
 
      * Dispose of the `Component` and all child components.
      *
      * @fires Component#dispose
+     *
+     * @param {Object} options
+     * @param {Element} options.originalEl element with which to replace player element
      */
 
 
     var _proto = Component.prototype;
 
-    _proto.dispose = function dispose() {
+    _proto.dispose = function dispose(options) {
+      if (options === void 0) {
+        options = {};
+      }
+
       // Bail out if the component has already been disposed.
       if (this.isDisposed_) {
         return;
       if (this.el_) {
         // Remove element from DOM
         if (this.el_.parentNode) {
-          this.el_.parentNode.removeChild(this.el_);
+          if (options.restoreEl) {
+            this.el_.parentNode.replaceChild(options.restoreEl, this.el_);
+          } else {
+            this.el_.parentNode.removeChild(this.el_);
+          }
         }
 
         this.el_ = null;
     ;
 
     _proto.initChildren = function initChildren() {
-      var _this = this;
+      var _this2 = this;
 
       var children = this.options_.children;
 
           // reach back into the player for options later.
 
 
-          opts.playerOptions = _this.options_.playerOptions; // Create and add the child component.
+          opts.playerOptions = _this2.options_.playerOptions; // Create and add the child component.
           // Add a direct reference to the child by name on the parent instance.
           // If two of the same component are used, different names should be supplied
           // for each
 
-          var newChild = _this.addChild(name, opts);
+          var newChild = _this2.addChild(name, opts);
 
           if (newChild) {
-            _this[name] = newChild;
+            _this2[name] = newChild;
           }
         }; // Allow for an array of children details to passed in the options
 
 
           if (typeof child === 'string') {
             name = child;
-            opts = children[name] || _this.options_[name] || {};
+            opts = children[name] || _this2.options_[name] || {};
           } else {
             name = child.name;
             opts = child;
     ;
 
     _proto.setTimeout = function setTimeout(fn, timeout) {
-      var _this2 = this;
+      var _this3 = this;
 
       // declare as variables so they are properly available in timeout function
       // eslint-disable-next-line
       fn = bind(this, fn);
       this.clearTimersOnDispose_();
       timeoutId = window.setTimeout(function () {
-        if (_this2.setTimeoutIds_.has(timeoutId)) {
-          _this2.setTimeoutIds_["delete"](timeoutId);
+        if (_this3.setTimeoutIds_.has(timeoutId)) {
+          _this3.setTimeoutIds_["delete"](timeoutId);
         }
 
         fn();
     ;
 
     _proto.requestAnimationFrame = function requestAnimationFrame(fn) {
-      var _this3 = this;
+      var _this4 = this;
 
       // Fall back to using a timer.
       if (!this.supportsRaf_) {
       var id;
       fn = bind(this, fn);
       id = window.requestAnimationFrame(function () {
-        if (_this3.rafIds_.has(id)) {
-          _this3.rafIds_["delete"](id);
+        if (_this4.rafIds_.has(id)) {
+          _this4.rafIds_["delete"](id);
         }
 
         fn();
     ;
 
     _proto.requestNamedAnimationFrame = function requestNamedAnimationFrame(name, fn) {
-      var _this4 = this;
+      var _this5 = this;
 
       if (this.namedRafs_.has(name)) {
         return;
       var id = this.requestAnimationFrame(function () {
         fn();
 
-        if (_this4.namedRafs_.has(name)) {
-          _this4.namedRafs_["delete"](name);
+        if (_this5.namedRafs_.has(name)) {
+          _this5.namedRafs_["delete"](name);
         }
       });
       this.namedRafs_.set(name, id);
     ;
 
     _proto.clearTimersOnDispose_ = function clearTimersOnDispose_() {
-      var _this5 = this;
+      var _this6 = this;
 
       if (this.clearingTimersOnDispose_) {
         return;
           // for a `Set` key will actually be the value again
           // so forEach((val, val) =>` but for maps we want to use
           // the key.
-          _this5[idName].forEach(function (val, key) {
-            return _this5[cancelName](key);
+          _this6[idName].forEach(function (val, key) {
+            return _this6[cancelName](key);
           });
         });
-        _this5.clearingTimersOnDispose_ = false;
+        _this6.clearingTimersOnDispose_ = false;
       });
     }
     /**
       var cues = new TextTrackCueList(_this.cues_);
       var activeCues = new TextTrackCueList(_this.activeCues_);
       var changed = false;
-      var timeupdateHandler = bind(assertThisInitialized(_this), function () {
-        if (!this.tech_.isReady_ || this.tech_.isDisposed()) {
+      _this.timeupdateHandler = bind(assertThisInitialized(_this), function () {
+        if (this.tech_.isDisposed()) {
+          return;
+        }
+
+        if (!this.tech_.isReady_) {
+          this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler);
           return;
         } // Accessing this.activeCues for the side-effects of updating itself
         // due to its nature as a getter function. Do not remove or cues will
           this.trigger('cuechange');
           changed = false;
         }
+
+        this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler);
       });
 
       var disposeHandler = function disposeHandler() {
-        _this.tech_.off('timeupdate', timeupdateHandler);
+        _this.stopTracking();
       };
 
       _this.tech_.one('dispose', disposeHandler);
 
       if (mode !== 'disabled') {
-        _this.tech_.on('timeupdate', timeupdateHandler);
+        _this.startTracking();
       }
 
       Object.defineProperties(assertThisInitialized(_this), {
               loadTrack(this.src, this);
             }
 
-            this.tech_.off('timeupdate', timeupdateHandler);
+            this.stopTracking();
 
             if (mode !== 'disabled') {
-              this.tech_.on('timeupdate', timeupdateHandler);
+              this.startTracking();
             }
             /**
              * An event that fires when mode changes on this track. This allows
 
       return _this;
     }
+
+    var _proto = TextTrack.prototype;
+
+    _proto.startTracking = function startTracking() {
+      this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler);
+    };
+
+    _proto.stopTracking = function stopTracking() {
+      if (this.rvf_) {
+        this.tech_.cancelVideoFrameCallback(this.rvf_);
+        this.rvf_ = undefined;
+      }
+    }
     /**
      * Add a cue to the internal list of cues.
      *
      * @param {TextTrack~Cue} cue
      *        The cue to add to our internal list
      */
-
-
-    var _proto = TextTrack.prototype;
+    ;
 
     _proto.addCue = function addCue(originalCue) {
       var cue = originalCue;
 
       _this.disposeSourceHandler_ = function (e) {
         return _this.disposeSourceHandler(e);
-      }; // keep track of whether the current source has played at all to
-      // implement a very limited played()
+      };
 
+      _this.queuedHanders_ = new Set(); // keep track of whether the current source has played at all to
+      // implement a very limited played()
 
       _this.hasStarted_ = false;
 
     ;
 
     _proto.setDisablePictureInPicture = function setDisablePictureInPicture() {}
+    /**
+     * A fallback implementation of requestVideoFrameCallback using requestAnimationFrame
+     *
+     * @param {function} cb
+     * @return {number} request id
+     */
+    ;
+
+    _proto.requestVideoFrameCallback = function requestVideoFrameCallback(cb) {
+      var _this8 = this;
+
+      var id = newGUID();
+
+      if (this.paused()) {
+        this.queuedHanders_.add(id);
+        this.one('playing', function () {
+          if (_this8.queuedHanders_.has(id)) {
+            _this8.queuedHanders_["delete"](id);
+
+            cb();
+          }
+        });
+      } else {
+        this.requestNamedAnimationFrame(id, cb);
+      }
+
+      return id;
+    }
+    /**
+     * A fallback implementation of cancelVideoFrameCallback
+     *
+     * @param {number} id id of callback to be cancelled
+     */
+    ;
+
+    _proto.cancelVideoFrameCallback = function cancelVideoFrameCallback(id) {
+      if (this.queuedHanders_.has(id)) {
+        this.queuedHanders_["delete"](id);
+      } else {
+        this.cancelNamedAnimationFrame(id);
+      }
+    }
     /**
      * A method to set a poster from a `Tech`.
      *
    */
 
   Tech.prototype.featuresNativeTextTracks = false;
+  /**
+   * Boolean indicating whether the `Tech` supports `requestVideoFrameCallback`.
+   *
+   * @type {boolean}
+   * @default
+   */
+
+  Tech.prototype.featuresVideoFrameCallback = false;
   /**
    * A functional mixin for techs that want to use the Source Handler pattern.
    * Source handlers are scripts for handling specific formats.
   /**
    * Mimetypes
    *
-   * @see http://hul.harvard.edu/ois/////systems/wax/wax-public-help/mimetypes.htm
+   * @see https://www.iana.org/assignments/media-types/media-types.xhtml
    * @typedef Mimetypes~Kind
    * @enum
    */
     oga: 'audio/ogg',
     wav: 'audio/wav',
     m3u8: 'application/x-mpegURL',
+    mpd: 'application/dash+xml',
     jpg: 'image/jpeg',
     jpeg: 'image/jpeg',
     gif: 'image/gif',
      *         The `Player` that this class should be attached to.
      *
      * @param  {Object} [options]
-     *         The key/value store of player options.
+     *         The key/value store of component options.
      *
      * @param  {function} [options.clickHandler]
      *         The function to call when the button is clicked / activated
+     *
+     * @param  {string} [options.controlText]
+     *         The text to set on the button
+     *
+     * @param  {string} [options.className]
+     *         A class or space separated list of classes to add the component
+     *
      */
     function ClickableComponent(player, options) {
       var _this;
 
       _this = _Component.call(this, player, options) || this;
 
+      if (_this.options_.controlText) {
+        _this.controlText(_this.options_.controlText);
+      }
+
       _this.handleMouseOver_ = function (e) {
         return _this.handleMouseOver(e);
       };
 
       _this.on(player, ['disablepictureinpicturechanged', 'loadedmetadata'], function (e) {
         return _this.handlePictureInPictureEnabledChange(e);
+      });
+
+      _this.on(player, ['loadedmetadata', 'audioonlymodechange', 'audiopostermodechange'], function () {
+        // This audio detection will not detect HLS or DASH audio-only streams because there was no reliable way to detect them at the time
+        var isSourceAudio = player.currentType().substring(0, 5) === 'audio';
+
+        if (isSourceAudio || player.audioPosterMode() || player.audioOnlyMode()) {
+          if (player.isInPictureInPicture()) {
+            player.exitPictureInPicture();
+          }
+
+          _this.hide();
+        } else {
+          _this.show();
+        }
       }); // TODO: Deactivate button on player emptied event.
 
 
 
       if (this.items && this.items.length <= this.hideThreshold_) {
         this.hide();
+        this.menu.contentEl_.removeAttribute('role');
       } else {
         this.show();
+        this.menu.contentEl_.setAttribute('role', 'menu');
       }
     }
     /**
       _this = _MenuItem.call(this, player, options) || this;
       _this.track = track;
       _this.cue = cue;
-      track.addEventListener('cuechange', bind(assertThisInitialized(_this), _this.update));
       return _this;
     }
     /**
       _MenuItem.prototype.handleClick.call(this);
 
       this.player_.currentTime(this.cue.startTime);
-      this.update(this.cue.startTime);
-    }
-    /**
-     * Update chapter menu item
-     *
-     * @param {EventTarget~Event} [event]
-     *        The `cuechange` event that caused this function to run.
-     *
-     * @listens TextTrack#cuechange
-     */
-    ;
-
-    _proto.update = function update(event) {
-      var cue = this.cue;
-      var currentTime = this.player_.currentTime(); // vjs.log(currentTime, cue.startTime);
-
-      this.selected(cue.startTime <= currentTime && currentTime < cue.endTime);
     };
 
     return ChaptersTrackMenuItem;
      *        The function to call when this function is ready.
      */
     function ChaptersButton(player, options, ready) {
-      return _TextTrackButton.call(this, player, options, ready) || this;
+      var _this;
+
+      _this = _TextTrackButton.call(this, player, options, ready) || this;
+
+      _this.selectCurrentItem_ = function () {
+        _this.items.forEach(function (item) {
+          item.selected(_this.track_.activeCues[0] === item.cue);
+        });
+      };
+
+      return _this;
     }
     /**
      * Builds the default DOM `className`.
     ;
 
     _proto.update = function update(event) {
-      if (!this.track_ || event && (event.type === 'addtrack' || event.type === 'removetrack')) {
-        this.setTrack(this.findChaptersTrack());
+      if (event && event.track && event.track.kind !== 'chapters') {
+        return;
       }
 
-      _TextTrackButton.prototype.update.call(this);
+      var track = this.findChaptersTrack();
+
+      if (track !== this.track_) {
+        this.setTrack(track);
+
+        _TextTrackButton.prototype.update.call(this);
+      } else if (!this.items || track && track.cues && track.cues.length !== this.items.length) {
+        // Update the menu initially or if the number of cues has changed since set
+        _TextTrackButton.prototype.update.call(this);
+      }
     }
     /**
      * Set the currently selected track for the chapters button.
           remoteTextTrackEl.removeEventListener('load', this.updateHandler_);
         }
 
+        this.track_.removeEventListener('cuechange', this.selectCurrentItem_);
         this.track_ = null;
       }
 
         if (_remoteTextTrackEl) {
           _remoteTextTrackEl.addEventListener('load', this.updateHandler_);
         }
+
+        this.track_.addEventListener('cuechange', this.selectCurrentItem_);
       }
     }
     /**
     _proto.createEl = function createEl() {
       return _Component.prototype.createEl.call(this, 'iframe', {
         className: 'vjs-resize-manager',
-        tabIndex: -1
+        tabIndex: -1,
+        title: this.localize('No content')
       }, {
         'aria-hidden': 'true'
       });
 
       _this.proxyWebkitFullscreen_();
 
+      _this.featuresVideoFrameCallback = _this.featuresVideoFrameCallback && _this.el_.tagName === 'VIDEO';
+
       _this.triggerReady();
 
       return _this;
       var endFn = function endFn() {
         this.trigger('fullscreenchange', {
           isFullscreen: false
-        }); // Safari will sometimes set controls on the videoelement when existing fullscreen.
+        }); // Safari will sometimes set contols on the videoelement when existing fullscreen.
 
         if (this.el_.controls && !this.options_.nativeControlsForTouch && this.controls()) {
           this.el_.controls = false;
     _proto.requestPictureInPicture = function requestPictureInPicture() {
       return this.el_.requestPictureInPicture();
     }
+    /**
+     * Native requestVideoFrameCallback if supported by browser/tech, or fallback
+     *
+     * @param {function} cb function to call
+     * @return {number} id of request
+     */
+    ;
+
+    _proto.requestVideoFrameCallback = function requestVideoFrameCallback(cb) {
+      if (this.featuresVideoFrameCallback) {
+        return this.el_.requestVideoFrameCallback(cb);
+      }
+
+      return _Tech.prototype.requestVideoFrameCallback.call(this, cb);
+    }
+    /**
+     * Native or fallback requestVideoFrameCallback
+     *
+     * @param {number} id request id to cancel
+     */
+    ;
+
+    _proto.cancelVideoFrameCallback = function cancelVideoFrameCallback(id) {
+      if (this.featuresVideoFrameCallback) {
+        this.el_.cancelVideoFrameCallback(id);
+      } else {
+        _Tech.prototype.cancelVideoFrameCallback.call(this, id);
+      }
+    }
     /**
      * A getter/setter for the `Html5` Tech's source object.
      * > Note: Please use {@link Html5#setSource}
    * @default
    */
 
-  Html5.prototype.featuresTimeupdateEvents = true; // HTML5 Feature detection and Device Fixes --------------------------------- //
+  Html5.prototype.featuresTimeupdateEvents = true;
+  /**
+   * Whether the HTML5 el supports `requestVideoFrameCallback`
+   *
+   * @type {boolean}
+   */
+
+  Html5.prototype.featuresVideoFrameCallback = !!(Html5.TEST_VID && Html5.TEST_VID.requestVideoFrameCallback); // HTML5 Feature detection and Device Fixes --------------------------------- //
 
   var canPlayType;
 
 
       _this.userActive_ = false; // Init debugEnabled_
 
-      _this.debugEnabled_ = false; // if the global option object was accidentally blown away by
+      _this.debugEnabled_ = false; // Init state audioOnlyMode_
+
+      _this.audioOnlyMode_ = false; // Init state audioPosterMode_
+
+      _this.audioPosterMode_ = false; // Init state audioOnlyCache_
+
+      _this.audioOnlyCache_ = {
+        playerHeight: null,
+        hiddenChildren: []
+      }; // if the global option object was accidentally blown away by
       // someone, bail early with an informative error
 
       if (!_this.options_ || !_this.options_.techOrder || !_this.options_.techOrder.length) {
 
       _this.breakpoints(_this.options_.breakpoints);
 
-      _this.responsive(_this.options_.responsive);
+      _this.responsive(_this.options_.responsive); // Calling both the audio mode methods after the player is fully
+      // setup to be able to listen to the events triggered by them
+
+
+      _this.on('ready', function () {
+        // Calling the audioPosterMode method first so that
+        // the audioOnlyMode can take precedence when both options are set to true
+        _this.audioPosterMode(_this.options_.audioPosterMode);
+
+        _this.audioOnlyMode(_this.options_.audioOnlyMode);
+      });
 
       return _this;
     }
         if (list && list.off) {
           list.off();
         }
-      }); // the actual .el_ is removed here
+      }); // the actual .el_ is removed here, or replaced if
 
-      _Component.prototype.dispose.call(this);
+      _Component.prototype.dispose.call(this, {
+        restoreEl: this.options_.restoreEl
+      });
     }
     /**
      * Create the `Player`'s DOM element.
 
 
       this.addClass(idClass);
-      setTextContent(this.styleEl_, "\n      ." + idClass + " {\n        width: " + width + "px;\n        height: " + height + "px;\n      }\n\n      ." + idClass + ".vjs-fluid {\n        padding-top: " + ratioMultiplier * 100 + "%;\n      }\n    ");
+      setTextContent(this.styleEl_, "\n      ." + idClass + " {\n        width: " + width + "px;\n        height: " + height + "px;\n      }\n\n      ." + idClass + ".vjs-fluid:not(.vjs-audio-only-mode) {\n        padding-top: " + ratioMultiplier * 100 + "%;\n      }\n    ");
     }
     /**
      * Load/Create an instance of playback {@link Tech} including element
         this.setTimeout(function () {
           this.error({
             code: 4,
-            message: this.localize(this.options_.notSupportedMessage)
+            message: this.options_.notSupportedMessage
           });
         }, 0);
         return;
           _this15.setTimeout(function () {
             this.error({
               code: 4,
-              message: this.localize(this.options_.notSupportedMessage)
+              message: this.options_.notSupportedMessage
             });
           }, 0); // we could not find an appropriate tech, but let's still notify the delegate that this is it
           // this needs a better comment about why this is needed
 
     _proto.resetProgressBar_ = function resetProgressBar_() {
       this.currentTime(0);
-      var _this$controlBar = this.controlBar,
-          durationDisplay = _this$controlBar.durationDisplay,
-          remainingTimeDisplay = _this$controlBar.remainingTimeDisplay;
+
+      var _ref3 = this.controlBar || {},
+          durationDisplay = _ref3.durationDisplay,
+          remainingTimeDisplay = _ref3.remainingTimeDisplay;
 
       if (durationDisplay) {
         durationDisplay.updateContent();
       }
 
       return !!this.isAudio_;
+    };
+
+    _proto.enableAudioOnlyUI_ = function enableAudioOnlyUI_() {
+      var _this19 = this;
+
+      // Update styling immediately to show the control bar so we can get its height
+      this.addClass('vjs-audio-only-mode');
+      var playerChildren = this.children();
+      var controlBar = this.getChild('ControlBar');
+      var controlBarHeight = controlBar && controlBar.currentHeight(); // Hide all player components except the control bar. Control bar components
+      // needed only for video are hidden with CSS
+
+      playerChildren.forEach(function (child) {
+        if (child === controlBar) {
+          return;
+        }
+
+        if (child.el_ && !child.hasClass('vjs-hidden')) {
+          child.hide();
+
+          _this19.audioOnlyCache_.hiddenChildren.push(child);
+        }
+      });
+      this.audioOnlyCache_.playerHeight = this.currentHeight(); // Set the player height the same as the control bar
+
+      this.height(controlBarHeight);
+      this.trigger('audioonlymodechange');
+    };
+
+    _proto.disableAudioOnlyUI_ = function disableAudioOnlyUI_() {
+      this.removeClass('vjs-audio-only-mode'); // Show player components that were previously hidden
+
+      this.audioOnlyCache_.hiddenChildren.forEach(function (child) {
+        return child.show();
+      }); // Reset player height
+
+      this.height(this.audioOnlyCache_.playerHeight);
+      this.trigger('audioonlymodechange');
+    }
+    /**
+     * Get the current audioOnlyMode state or set audioOnlyMode to true or false.
+     *
+     * Setting this to `true` will hide all player components except the control bar,
+     * as well as control bar components needed only for video.
+     *
+     * @param {boolean} [value]
+     *         The value to set audioOnlyMode to.
+     *
+     * @return {Promise|boolean}
+     *        A Promise is returned when setting the state, and a boolean when getting
+     *        the present state
+     */
+    ;
+
+    _proto.audioOnlyMode = function audioOnlyMode(value) {
+      var _this20 = this;
+
+      if (typeof value !== 'boolean' || value === this.audioOnlyMode_) {
+        return this.audioOnlyMode_;
+      }
+
+      this.audioOnlyMode_ = value;
+      var PromiseClass = this.options_.Promise || window.Promise;
+
+      if (PromiseClass) {
+        // Enable Audio Only Mode
+        if (value) {
+          var exitPromises = []; // Fullscreen and PiP are not supported in audioOnlyMode, so exit if we need to.
+
+          if (this.isInPictureInPicture()) {
+            exitPromises.push(this.exitPictureInPicture());
+          }
+
+          if (this.isFullscreen()) {
+            exitPromises.push(this.exitFullscreen());
+          }
+
+          if (this.audioPosterMode()) {
+            exitPromises.push(this.audioPosterMode(false));
+          }
+
+          return PromiseClass.all(exitPromises).then(function () {
+            return _this20.enableAudioOnlyUI_();
+          });
+        } // Disable Audio Only Mode
+
+
+        return PromiseClass.resolve().then(function () {
+          return _this20.disableAudioOnlyUI_();
+        });
+      }
+
+      if (value) {
+        if (this.isInPictureInPicture()) {
+          this.exitPictureInPicture();
+        }
+
+        if (this.isFullscreen()) {
+          this.exitFullscreen();
+        }
+
+        this.enableAudioOnlyUI_();
+      } else {
+        this.disableAudioOnlyUI_();
+      }
+    };
+
+    _proto.enablePosterModeUI_ = function enablePosterModeUI_() {
+      // Hide the video element and show the poster image to enable posterModeUI
+      var tech = this.tech_ && this.tech_;
+      tech.hide();
+      this.addClass('vjs-audio-poster-mode');
+      this.trigger('audiopostermodechange');
+    };
+
+    _proto.disablePosterModeUI_ = function disablePosterModeUI_() {
+      // Show the video element and hide the poster image to disable posterModeUI
+      var tech = this.tech_ && this.tech_;
+      tech.show();
+      this.removeClass('vjs-audio-poster-mode');
+      this.trigger('audiopostermodechange');
+    }
+    /**
+     * Get the current audioPosterMode state or set audioPosterMode to true or false
+     *
+     * @param {boolean} [value]
+     *         The value to set audioPosterMode to.
+     *
+     * @return {Promise|boolean}
+     *         A Promise is returned when setting the state, and a boolean when getting
+     *        the present state
+     */
+    ;
+
+    _proto.audioPosterMode = function audioPosterMode(value) {
+      var _this21 = this;
+
+      if (typeof value !== 'boolean' || value === this.audioPosterMode_) {
+        return this.audioPosterMode_;
+      }
+
+      this.audioPosterMode_ = value;
+      var PromiseClass = this.options_.Promise || window.Promise;
+
+      if (PromiseClass) {
+        if (value) {
+          if (this.audioOnlyMode()) {
+            var audioOnlyModePromise = this.audioOnlyMode(false);
+            return audioOnlyModePromise.then(function () {
+              // enable audio poster mode after audio only mode is disabled
+              _this21.enablePosterModeUI_();
+            });
+          }
+
+          return PromiseClass.resolve().then(function () {
+            // enable audio poster mode
+            _this21.enablePosterModeUI_();
+          });
+        }
+
+        return PromiseClass.resolve().then(function () {
+          // disable audio poster mode
+          _this21.disablePosterModeUI_();
+        });
+      }
+
+      if (value) {
+        if (this.audioOnlyMode()) {
+          this.audioOnlyMode(false);
+        }
+
+        this.enablePosterModeUI_();
+        return;
+      }
+
+      this.disablePosterModeUI_();
     }
     /**
      * A helper method for adding a {@link TextTrack} to our
     ;
 
     _proto.createModal = function createModal(content, options) {
-      var _this19 = this;
+      var _this22 = this;
 
       options = options || {};
       options.content = content || '';
       var modal = new ModalDialog(this, options);
       this.addChild(modal);
       modal.on('dispose', function () {
-        _this19.removeChild(modal);
+        _this22.removeChild(modal);
       });
       modal.open();
       return modal;
     ;
 
     _proto.loadMedia = function loadMedia(media, ready) {
-      var _this20 = this;
+      var _this23 = this;
 
       if (!media || typeof media !== 'object') {
         return;
 
       if (Array.isArray(textTracks)) {
         textTracks.forEach(function (tt) {
-          return _this20.addRemoteTextTrack(tt, false);
+          return _this23.addRemoteTextTrack(tt, false);
         });
       }
 
       }
     },
     breakpoints: {},
-    responsive: false
+    responsive: false,
+    audioOnlyMode: false,
+    audioPosterMode: false
   };
   [
   /**
       log$1.warn('The element supplied is not included in the DOM');
     }
 
-    options = options || {};
+    options = options || {}; // Store a copy of the el before modification, if it is to be restored in destroy()
+    // If div ingest, store the parent div
+
+    if (options.restoreEl === true) {
+      options.restoreEl = (el.parentNode && el.parentNode.hasAttribute('data-vjs-player') ? el.parentNode : el).cloneNode(true);
+    }
+
     hooks('beforesetup').forEach(function (hookFunction) {
       var opts = hookFunction(el, mergeOptions$3(options));
 
         head.insertBefore(style, head.firstChild);
       }
 
-      setTextContent(style, "\n      .video-js {\n        width: 300px;\n        height: 150px;\n      }\n\n      .vjs-fluid {\n        padding-top: 56.25%\n      }\n    ");
+      setTextContent(style, "\n      .video-js {\n        width: 300px;\n        height: 150px;\n      }\n\n      .vjs-fluid:not(.vjs-audio-only-mode) {\n        padding-top: 56.25%\n      }\n    ");
     }
   } // Run Auto-load players
   // You have to wait at least once in case this script is loaded after your
     return array;
   }
 
-  /*! @name m3u8-parser @version 4.7.0 @license Apache-2.0 */
+  /*! @name m3u8-parser @version 4.7.1 @license Apache-2.0 */
   /**
    * A stream that buffers string input and generates a `data` event for each
    * line.
                     attributes: entry.attributes
                   };
                   return;
+                }
+
+                if (entry.attributes.KEYFORMAT === 'com.microsoft.playready') {
+                  this.manifest.contentProtection = this.manifest.contentProtection || {}; // TODO: add full support for this.
+
+                  this.manifest.contentProtection['com.microsoft.playready'] = {
+                    uri: entry.attributes.URI
+                  };
+                  return;
                 } // check if the content is encrypted for Widevine
                 // Widevine/HLS spec: https://storage.googleapis.com/wvdocs/Widevine_DRM_HLS.pdf
 
     return null;
   };
 
+  // const log2 = Math.log2 ? Math.log2 : (x) => (Math.log(x) / Math.log(2));
+  // we used to do this with log2 but BigInt does not support builtin math
+  // Math.ceil(log2(x));
+
+
+  var countBits = function countBits(x) {
+    return x.toString(2).length;
+  }; // count the number of whole bytes it would take to represent a number
+
+  var countBytes = function countBytes(x) {
+    return Math.ceil(countBits(x) / 8);
+  };
+  var isArrayBufferView = function isArrayBufferView(obj) {
+    if (ArrayBuffer.isView === 'function') {
+      return ArrayBuffer.isView(obj);
+    }
+
+    return obj && obj.buffer instanceof ArrayBuffer;
+  };
+  var isTypedArray = function isTypedArray(obj) {
+    return isArrayBufferView(obj);
+  };
+  var toUint8 = function toUint8(bytes) {
+    if (bytes instanceof Uint8Array) {
+      return bytes;
+    }
+
+    if (!Array.isArray(bytes) && !isTypedArray(bytes) && !(bytes instanceof ArrayBuffer)) {
+      // any non-number or NaN leads to empty uint8array
+      // eslint-disable-next-line
+      if (typeof bytes !== 'number' || typeof bytes === 'number' && bytes !== bytes) {
+        bytes = 0;
+      } else {
+        bytes = [bytes];
+      }
+    }
+
+    return new Uint8Array(bytes && bytes.buffer || bytes, bytes && bytes.byteOffset || 0, bytes && bytes.byteLength || 0);
+  };
+  var BigInt = window.BigInt || Number;
+  var BYTE_TABLE = [BigInt('0x1'), BigInt('0x100'), BigInt('0x10000'), BigInt('0x1000000'), BigInt('0x100000000'), BigInt('0x10000000000'), BigInt('0x1000000000000'), BigInt('0x100000000000000'), BigInt('0x10000000000000000')];
+  var bytesToNumber = function bytesToNumber(bytes, _temp) {
+    var _ref = _temp === void 0 ? {} : _temp,
+        _ref$signed = _ref.signed,
+        signed = _ref$signed === void 0 ? false : _ref$signed,
+        _ref$le = _ref.le,
+        le = _ref$le === void 0 ? false : _ref$le;
+
+    bytes = toUint8(bytes);
+    var fn = le ? 'reduce' : 'reduceRight';
+    var obj = bytes[fn] ? bytes[fn] : Array.prototype[fn];
+    var number = obj.call(bytes, function (total, _byte, i) {
+      var exponent = le ? i : Math.abs(i + 1 - bytes.length);
+      return total + BigInt(_byte) * BYTE_TABLE[exponent];
+    }, BigInt(0));
+
+    if (signed) {
+      var max = BYTE_TABLE[bytes.length] / BigInt(2) - BigInt(1);
+      number = BigInt(number);
+
+      if (number > max) {
+        number -= max;
+        number -= max;
+        number -= BigInt(2);
+      }
+    }
+
+    return Number(number);
+  };
+  var numberToBytes = function numberToBytes(number, _temp2) {
+    var _ref2 = _temp2 === void 0 ? {} : _temp2,
+        _ref2$le = _ref2.le,
+        le = _ref2$le === void 0 ? false : _ref2$le; // eslint-disable-next-line
+
+
+    if (typeof number !== 'bigint' && typeof number !== 'number' || typeof number === 'number' && number !== number) {
+      number = 0;
+    }
+
+    number = BigInt(number);
+    var byteCount = countBytes(number);
+    var bytes = new Uint8Array(new ArrayBuffer(byteCount));
+
+    for (var i = 0; i < byteCount; i++) {
+      var byteIndex = le ? i : Math.abs(i + 1 - bytes.length);
+      bytes[byteIndex] = Number(number / BYTE_TABLE[i] & BigInt(0xFF));
+
+      if (number < 0) {
+        bytes[byteIndex] = Math.abs(~bytes[byteIndex]);
+        bytes[byteIndex] -= i === 0 ? 1 : 2;
+      }
+    }
+
+    return bytes;
+  };
+  var stringToBytes = function stringToBytes(string, stringIsBytes) {
+    if (typeof string !== 'string' && string && typeof string.toString === 'function') {
+      string = string.toString();
+    }
+
+    if (typeof string !== 'string') {
+      return new Uint8Array();
+    } // If the string already is bytes, we don't have to do this
+    // otherwise we do this so that we split multi length characters
+    // into individual bytes
+
+
+    if (!stringIsBytes) {
+      string = unescape(encodeURIComponent(string));
+    }
+
+    var view = new Uint8Array(string.length);
+
+    for (var i = 0; i < string.length; i++) {
+      view[i] = string.charCodeAt(i);
+    }
+
+    return view;
+  };
+  var concatTypedArrays = function concatTypedArrays() {
+    for (var _len = arguments.length, buffers = new Array(_len), _key = 0; _key < _len; _key++) {
+      buffers[_key] = arguments[_key];
+    }
+
+    buffers = buffers.filter(function (b) {
+      return b && (b.byteLength || b.length) && typeof b !== 'string';
+    });
+
+    if (buffers.length <= 1) {
+      // for 0 length we will return empty uint8
+      // for 1 length we return the first uint8
+      return toUint8(buffers[0]);
+    }
+
+    var totalLen = buffers.reduce(function (total, buf, i) {
+      return total + (buf.byteLength || buf.length);
+    }, 0);
+    var tempBuffer = new Uint8Array(totalLen);
+    var offset = 0;
+    buffers.forEach(function (buf) {
+      buf = toUint8(buf);
+      tempBuffer.set(buf, offset);
+      offset += buf.byteLength;
+    });
+    return tempBuffer;
+  };
+  /**
+   * Check if the bytes "b" are contained within bytes "a".
+   *
+   * @param {Uint8Array|Array} a
+   *        Bytes to check in
+   *
+   * @param {Uint8Array|Array} b
+   *        Bytes to check for
+   *
+   * @param {Object} options
+   *        options
+   *
+   * @param {Array|Uint8Array} [offset=0]
+   *        offset to use when looking at bytes in a
+   *
+   * @param {Array|Uint8Array} [mask=[]]
+   *        mask to use on bytes before comparison.
+   *
+   * @return {boolean}
+   *         If all bytes in b are inside of a, taking into account
+   *         bit masks.
+   */
+
+  var bytesMatch = function bytesMatch(a, b, _temp3) {
+    var _ref3 = _temp3 === void 0 ? {} : _temp3,
+        _ref3$offset = _ref3.offset,
+        offset = _ref3$offset === void 0 ? 0 : _ref3$offset,
+        _ref3$mask = _ref3.mask,
+        mask = _ref3$mask === void 0 ? [] : _ref3$mask;
+
+    a = toUint8(a);
+    b = toUint8(b); // ie 11 does not support uint8 every
+
+    var fn = b.every ? b.every : Array.prototype.every;
+    return b.length && a.length - offset >= b.length && // ie 11 doesn't support every on uin8
+    fn.call(b, function (bByte, i) {
+      var aByte = mask[i] ? mask[i] & a[offset + i] : a[offset + i];
+      return bByte === aByte;
+    });
+  };
+
   /**
    * Loops through all supported media groups in master and calls the provided
    * callback for each group
 
   var DOMParser = domParser.DOMParser;
 
-  /*! @name mpd-parser @version 0.21.0 @license Apache-2.0 */
+  /*! @name mpd-parser @version 0.21.1 @license Apache-2.0 */
 
   var isObject = function isObject(obj) {
     return !!obj && typeof obj === 'object';
 
   var generateKeySystemInformation = function generateKeySystemInformation(contentProtectionNodes) {
     return contentProtectionNodes.reduce(function (acc, node) {
-      var attributes = parseAttributes(node);
+      var attributes = parseAttributes(node); // Although it could be argued that according to the UUID RFC spec the UUID string (a-f chars) should be generated
+      // as a lowercase string it also mentions it should be treated as case-insensitive on input. Since the key system
+      // UUIDs in the keySystemsMap are hardcoded as lowercase in the codebase there isn't any reason not to do
+      // .toLowerCase() on the input UUID string from the manifest (at least I could not think of one).
+
+      if (attributes.schemeIdUri) {
+        attributes.schemeIdUri = attributes.schemeIdUri.toLowerCase();
+      }
+
       var keySystem = keySystemsMap[attributes.schemeIdUri];
 
       if (keySystem) {
 
         if (psshNode) {
           var pssh = getContent(psshNode);
-          var psshBuffer = pssh && decodeB64ToUint8Array(pssh);
-          acc[keySystem].pssh = psshBuffer;
+          acc[keySystem].pssh = pssh && decodeB64ToUint8Array(pssh);
         }
       }
 
 
   var parseSidx_1 = parseSidx;
 
-  // const log2 = Math.log2 ? Math.log2 : (x) => (Math.log(x) / Math.log(2));
-  // we used to do this with log2 but BigInt does not support builtin math
-  // Math.ceil(log2(x));
-
-
-  var countBits = function countBits(x) {
-    return x.toString(2).length;
-  }; // count the number of whole bytes it would take to represent a number
-
-  var countBytes = function countBytes(x) {
-    return Math.ceil(countBits(x) / 8);
-  };
-  var isTypedArray = function isTypedArray(obj) {
-    return ArrayBuffer.isView(obj);
-  };
-  var toUint8 = function toUint8(bytes) {
-    if (bytes instanceof Uint8Array) {
-      return bytes;
-    }
-
-    if (!Array.isArray(bytes) && !isTypedArray(bytes) && !(bytes instanceof ArrayBuffer)) {
-      // any non-number or NaN leads to empty uint8array
-      // eslint-disable-next-line
-      if (typeof bytes !== 'number' || typeof bytes === 'number' && bytes !== bytes) {
-        bytes = 0;
-      } else {
-        bytes = [bytes];
-      }
-    }
-
-    return new Uint8Array(bytes && bytes.buffer || bytes, bytes && bytes.byteOffset || 0, bytes && bytes.byteLength || 0);
-  };
-  var BigInt = window.BigInt || Number;
-  var BYTE_TABLE = [BigInt('0x1'), BigInt('0x100'), BigInt('0x10000'), BigInt('0x1000000'), BigInt('0x100000000'), BigInt('0x10000000000'), BigInt('0x1000000000000'), BigInt('0x100000000000000'), BigInt('0x10000000000000000')];
-  var bytesToNumber = function bytesToNumber(bytes, _temp) {
-    var _ref = _temp === void 0 ? {} : _temp,
-        _ref$signed = _ref.signed,
-        signed = _ref$signed === void 0 ? false : _ref$signed,
-        _ref$le = _ref.le,
-        le = _ref$le === void 0 ? false : _ref$le;
-
-    bytes = toUint8(bytes);
-    var fn = le ? 'reduce' : 'reduceRight';
-    var obj = bytes[fn] ? bytes[fn] : Array.prototype[fn];
-    var number = obj.call(bytes, function (total, _byte, i) {
-      var exponent = le ? i : Math.abs(i + 1 - bytes.length);
-      return total + BigInt(_byte) * BYTE_TABLE[exponent];
-    }, BigInt(0));
-
-    if (signed) {
-      var max = BYTE_TABLE[bytes.length] / BigInt(2) - BigInt(1);
-      number = BigInt(number);
-
-      if (number > max) {
-        number -= max;
-        number -= max;
-        number -= BigInt(2);
-      }
-    }
-
-    return Number(number);
-  };
-  var numberToBytes = function numberToBytes(number, _temp2) {
-    var _ref2 = _temp2 === void 0 ? {} : _temp2,
-        _ref2$le = _ref2.le,
-        le = _ref2$le === void 0 ? false : _ref2$le; // eslint-disable-next-line
-
-
-    if (typeof number !== 'bigint' && typeof number !== 'number' || typeof number === 'number' && number !== number) {
-      number = 0;
-    }
-
-    number = BigInt(number);
-    var byteCount = countBytes(number);
-    var bytes = new Uint8Array(new ArrayBuffer(byteCount));
-
-    for (var i = 0; i < byteCount; i++) {
-      var byteIndex = le ? i : Math.abs(i + 1 - bytes.length);
-      bytes[byteIndex] = Number(number / BYTE_TABLE[i] & BigInt(0xFF));
-
-      if (number < 0) {
-        bytes[byteIndex] = Math.abs(~bytes[byteIndex]);
-        bytes[byteIndex] -= i === 0 ? 1 : 2;
-      }
-    }
-
-    return bytes;
-  };
-  var stringToBytes = function stringToBytes(string, stringIsBytes) {
-    if (typeof string !== 'string' && string && typeof string.toString === 'function') {
-      string = string.toString();
-    }
-
-    if (typeof string !== 'string') {
-      return new Uint8Array();
-    } // If the string already is bytes, we don't have to do this
-    // otherwise we do this so that we split multi length characters
-    // into individual bytes
-
-
-    if (!stringIsBytes) {
-      string = unescape(encodeURIComponent(string));
-    }
-
-    var view = new Uint8Array(string.length);
-
-    for (var i = 0; i < string.length; i++) {
-      view[i] = string.charCodeAt(i);
-    }
-
-    return view;
-  };
-  var concatTypedArrays = function concatTypedArrays() {
-    for (var _len = arguments.length, buffers = new Array(_len), _key = 0; _key < _len; _key++) {
-      buffers[_key] = arguments[_key];
-    }
-
-    buffers = buffers.filter(function (b) {
-      return b && (b.byteLength || b.length) && typeof b !== 'string';
-    });
-
-    if (buffers.length <= 1) {
-      // for 0 length we will return empty uint8
-      // for 1 length we return the first uint8
-      return toUint8(buffers[0]);
-    }
-
-    var totalLen = buffers.reduce(function (total, buf, i) {
-      return total + (buf.byteLength || buf.length);
-    }, 0);
-    var tempBuffer = new Uint8Array(totalLen);
-    var offset = 0;
-    buffers.forEach(function (buf) {
-      buf = toUint8(buf);
-      tempBuffer.set(buf, offset);
-      offset += buf.byteLength;
-    });
-    return tempBuffer;
-  };
-  /**
-   * Check if the bytes "b" are contained within bytes "a".
-   *
-   * @param {Uint8Array|Array} a
-   *        Bytes to check in
-   *
-   * @param {Uint8Array|Array} b
-   *        Bytes to check for
-   *
-   * @param {Object} options
-   *        options
-   *
-   * @param {Array|Uint8Array} [offset=0]
-   *        offset to use when looking at bytes in a
-   *
-   * @param {Array|Uint8Array} [mask=[]]
-   *        mask to use on bytes before comparison.
-   *
-   * @return {boolean}
-   *         If all bytes in b are inside of a, taking into account
-   *         bit masks.
-   */
-
-  var bytesMatch = function bytesMatch(a, b, _temp3) {
-    var _ref3 = _temp3 === void 0 ? {} : _temp3,
-        _ref3$offset = _ref3.offset,
-        offset = _ref3$offset === void 0 ? 0 : _ref3$offset,
-        _ref3$mask = _ref3.mask,
-        mask = _ref3$mask === void 0 ? [] : _ref3$mask;
-
-    a = toUint8(a);
-    b = toUint8(b); // ie 11 does not support uint8 every
-
-    var fn = b.every ? b.every : Array.prototype.every;
-    return b.length && a.length - offset >= b.length && // ie 11 doesn't support every on uin8
-    fn.call(b, function (bByte, i) {
-      var aByte = mask[i] ? mask[i] & a[offset + i] : a[offset + i];
-      return bByte === aByte;
-    });
-  };
-
   var ID3 = toUint8([0x49, 0x44, 0x33]);
   var getId3Size = function getId3Size(bytes, offset) {
     if (offset === void 0) {
   };
   var clock_1 = clock.ONE_SECOND_IN_TS;
 
-  /*! @name @videojs/http-streaming @version 2.13.1 @license Apache-2.0 */
+  /*! @name @videojs/http-streaming @version 2.14.2 @license Apache-2.0 */
   /**
    * @file resolve-url.js - Handling how URLs are resolved and manipulated
    */
 
       for (var _i2 = 0; _i2 < properties.playlists.length; _i2++) {
         if (newMedia.id === properties.playlists[_i2].id) {
-          properties.playlists[_i2] = newMedia;
+          properties.playlists[_i2] = mergedPlaylist;
         }
       }
     });
     Object.keys(message).forEach(function (key) {
       var value = message[key];
 
-      if (ArrayBuffer.isView(value)) {
+      if (isArrayBufferView(value)) {
         transferable[key] = {
           bytes: value.buffer,
           byteOffset: value.byteOffset,
   var getWorkerString = function getWorkerString(fn) {
     return fn.toString().replace(/^function.+?{/, '').slice(0, -1);
   };
-  /* rollup-plugin-worker-factory start for worker!/Users/gsinger/repos/clean/http-streaming/src/transmuxer-worker.js */
+  /* rollup-plugin-worker-factory start for worker!/Users/bclifford/Code/vhs-release-test/src/transmuxer-worker.js */
 
 
   var workerCode$1 = transform(getWorkerString(function () {
     };
   }));
   var TransmuxWorker = factory(workerCode$1);
-  /* rollup-plugin-worker-factory end for worker!/Users/gsinger/repos/clean/http-streaming/src/transmuxer-worker.js */
+  /* rollup-plugin-worker-factory end for worker!/Users/bclifford/Code/vhs-release-test/src/transmuxer-worker.js */
 
   var handleData_ = function handleData_(event, transmuxedData, callback) {
     var _event$data$segment = event.data.segment,
       _this.timelineChangeController_ = settings.timelineChangeController;
       _this.shouldSaveSegmentTimingInfo_ = true;
       _this.parse708captions_ = settings.parse708captions;
+      _this.useDtsForTimestampOffset_ = settings.useDtsForTimestampOffset;
       _this.captionServices_ = settings.captionServices;
       _this.experimentalExactManifestTimings = settings.experimentalExactManifestTimings; // private instance variables
 
       // the video, this will trim the start of the audio.
       // This also trims any offset from 0 at the beginning of the media
 
-      segmentInfo.timestampOffset -= segmentInfo.timingInfo.start; // In the event that there are part segment downloads, each will try to update the
+      segmentInfo.timestampOffset -= this.getSegmentStartTimeForTimestampOffsetCalculation_({
+        videoTimingInfo: segmentInfo.segment.videoTimingInfo,
+        audioTimingInfo: segmentInfo.segment.audioTimingInfo,
+        timingInfo: segmentInfo.timingInfo
+      }); // In the event that there are part segment downloads, each will try to update the
       // timestamp offset. Retaining this bit of state prevents us from updating in the
       // future (within the same segment), however, there may be a better way to handle it.
 
       }
     };
 
+    _proto.getSegmentStartTimeForTimestampOffsetCalculation_ = function getSegmentStartTimeForTimestampOffsetCalculation_(_ref10) {
+      var videoTimingInfo = _ref10.videoTimingInfo,
+          audioTimingInfo = _ref10.audioTimingInfo,
+          timingInfo = _ref10.timingInfo;
+
+      if (!this.useDtsForTimestampOffset_) {
+        return timingInfo.start;
+      }
+
+      if (videoTimingInfo && typeof videoTimingInfo.transmuxedDecodeStart === 'number') {
+        return videoTimingInfo.transmuxedDecodeStart;
+      } // handle audio only
+
+
+      if (audioTimingInfo && typeof audioTimingInfo.transmuxedDecodeStart === 'number') {
+        return audioTimingInfo.transmuxedDecodeStart;
+      } // handle content not transmuxed (e.g., MP4)
+
+
+      return timingInfo.start;
+    };
+
     _proto.updateTimingInfoEnd_ = function updateTimingInfoEnd_(segmentInfo) {
       segmentInfo.timingInfo = segmentInfo.timingInfo || {};
       var trackInfo = this.getMediaInfo_();
 
     return TimelineChangeController;
   }(videojs.EventTarget);
-  /* rollup-plugin-worker-factory start for worker!/Users/gsinger/repos/clean/http-streaming/src/decrypter-worker.js */
+  /* rollup-plugin-worker-factory start for worker!/Users/bclifford/Code/vhs-release-test/src/decrypter-worker.js */
 
 
   var workerCode = transform(getWorkerString(function () {
+    var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
+
     function createCommonjsModule(fn, basedir, module) {
       return module = {
         path: basedir,
     function unpad(padded) {
       return padded.subarray(0, padded.byteLength - padded[padded.byteLength - 1]);
     }
-    /*! @name aes-decrypter @version 3.1.2 @license Apache-2.0 */
+    /*! @name aes-decrypter @version 3.1.3 @license Apache-2.0 */
 
     /**
      * @file aes.js
       }]);
       return Decrypter;
     }();
-    /**
-     * @file bin-utils.js
-     */
 
+    var win;
+
+    if (typeof window !== "undefined") {
+      win = window;
+    } else if (typeof commonjsGlobal !== "undefined") {
+      win = commonjsGlobal;
+    } else if (typeof self !== "undefined") {
+      win = self;
+    } else {
+      win = {};
+    }
+
+    var window_1 = win;
+
+    var isArrayBufferView = function isArrayBufferView(obj) {
+      if (ArrayBuffer.isView === 'function') {
+        return ArrayBuffer.isView(obj);
+      }
+
+      return obj && obj.buffer instanceof ArrayBuffer;
+    };
+
+    var BigInt = window_1.BigInt || Number;
+    [BigInt('0x1'), BigInt('0x100'), BigInt('0x10000'), BigInt('0x1000000'), BigInt('0x100000000'), BigInt('0x10000000000'), BigInt('0x1000000000000'), BigInt('0x100000000000000'), BigInt('0x10000000000000000')];
     /**
      * Creates an object for sending to a web worker modifying properties that are TypedArrays
      * into a new object with seperated properties for the buffer, byteOffset, and byteLength.
       Object.keys(message).forEach(function (key) {
         var value = message[key];
 
-        if (ArrayBuffer.isView(value)) {
+        if (isArrayBufferView(value)) {
           transferable[key] = {
             bytes: value.buffer,
             byteOffset: value.byteOffset,
     };
   }));
   var Decrypter = factory(workerCode);
-  /* rollup-plugin-worker-factory end for worker!/Users/gsinger/repos/clean/http-streaming/src/decrypter-worker.js */
+  /* rollup-plugin-worker-factory end for worker!/Users/bclifford/Code/vhs-release-test/src/decrypter-worker.js */
 
   /**
    * Convert the properties of an HLS track into an audioTrackKind.
       var segmentLoaderSettings = {
         vhs: _this.vhs_,
         parse708captions: options.parse708captions,
+        useDtsForTimestampOffset: options.useDtsForTimestampOffset,
         captionServices: captionServices,
         mediaSource: _this.mediaSource,
         currentTime: _this.tech_.currentTime.bind(_this.tech_),
     initPlugin(this, options);
   };
 
-  var version$4 = "2.13.1";
+  var version$4 = "2.14.2";
   var version$3 = "6.0.1";
-  var version$2 = "0.21.0";
-  var version$1 = "4.7.0";
-  var version = "3.1.2";
+  var version$2 = "0.21.1";
+  var version$1 = "4.7.1";
+  var version = "3.1.3";
   var Vhs = {
     PlaylistLoader: PlaylistLoader,
     Playlist: Playlist,
       _this = _Component.call(this, tech, videojs.mergeOptions(options.hls, options.vhs)) || this;
 
       if (options.hls && Object.keys(options.hls).length) {
-        videojs.log.warn('Using hls options is deprecated. Use vhs instead.');
+        videojs.log.warn('Using hls options is deprecated. Please rename `hls` to `vhs` in your options object.');
       } // if a tech level `initialBandwidth` option was passed
       // use that over the VHS level `bandwidth` option
 
       this.options_.smoothQualityChange = this.options_.smoothQualityChange || false;
       this.options_.useBandwidthFromLocalStorage = typeof this.source_.useBandwidthFromLocalStorage !== 'undefined' ? this.source_.useBandwidthFromLocalStorage : this.options_.useBandwidthFromLocalStorage || false;
       this.options_.useNetworkInformationApi = this.options_.useNetworkInformationApi || false;
+      this.options_.useDtsForTimestampOffset = this.options_.useDtsForTimestampOffset || false;
       this.options_.customTagParsers = this.options_.customTagParsers || [];
       this.options_.customTagMappers = this.options_.customTagMappers || [];
       this.options_.cacheEncryptionKeys = this.options_.cacheEncryptionKeys || false;
 
       this.options_.enableLowInitialPlaylist = this.options_.enableLowInitialPlaylist && this.options_.bandwidth === Config.INITIAL_BANDWIDTH; // grab options passed to player.src
 
-      ['withCredentials', 'useDevicePixelRatio', 'limitRenditionByPlayerDimensions', 'bandwidth', 'smoothQualityChange', 'customTagParsers', 'customTagMappers', 'handleManifestRedirects', 'cacheEncryptionKeys', 'playlistSelector', 'initialPlaylistSelector', 'experimentalBufferBasedABR', 'liveRangeSafeTimeDelta', 'experimentalLLHLS', 'useNetworkInformationApi', 'experimentalExactManifestTimings', 'experimentalLeastPixelDiffSelector'].forEach(function (option) {
+      ['withCredentials', 'useDevicePixelRatio', 'limitRenditionByPlayerDimensions', 'bandwidth', 'smoothQualityChange', 'customTagParsers', 'customTagMappers', 'handleManifestRedirects', 'cacheEncryptionKeys', 'playlistSelector', 'initialPlaylistSelector', 'experimentalBufferBasedABR', 'liveRangeSafeTimeDelta', 'experimentalLLHLS', 'useNetworkInformationApi', 'useDtsForTimestampOffset', 'experimentalExactManifestTimings', 'experimentalLeastPixelDiffSelector'].forEach(function (option) {
         if (typeof _this2.source_[option] !== 'undefined') {
           _this2.options_[option] = _this2.source_[option];
         }
 
   return videojs;
 
-})));
\ No newline at end of file
+})));