@clappr/hlsjs-playback 1.9.11 → 1.9.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,147 +1,4 @@
1
- import { Utils, Events as Events$1, Playback, Log, PlayerError, HTML5Video } from '@clappr/core';
2
-
3
- function _arrayLikeToArray(r, a) {
4
- (null == a || a > r.length) && (a = r.length);
5
- for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
6
- return n;
7
- }
8
- function _arrayWithoutHoles(r) {
9
- if (Array.isArray(r)) return _arrayLikeToArray(r);
10
- }
11
- function _assertThisInitialized(e) {
12
- if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
13
- return e;
14
- }
15
- function _callSuper(t, o, e) {
16
- return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e));
17
- }
18
- function _classCallCheck(a, n) {
19
- if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
20
- }
21
- function _defineProperties(e, r) {
22
- for (var t = 0; t < r.length; t++) {
23
- var o = r[t];
24
- o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey$1(o.key), o);
25
- }
26
- }
27
- function _createClass(e, r, t) {
28
- return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
29
- writable: !1
30
- }), e;
31
- }
32
- function _defineProperty$1(e, r, t) {
33
- return (r = _toPropertyKey$1(r)) in e ? Object.defineProperty(e, r, {
34
- value: t,
35
- enumerable: !0,
36
- configurable: !0,
37
- writable: !0
38
- }) : e[r] = t, e;
39
- }
40
- function _get() {
41
- return _get = "undefined" != typeof Reflect && Reflect.get ? Reflect.get.bind() : function (e, t, r) {
42
- var p = _superPropBase(e, t);
43
- if (p) {
44
- var n = Object.getOwnPropertyDescriptor(p, t);
45
- return n.get ? n.get.call(arguments.length < 3 ? e : r) : n.value;
46
- }
47
- }, _get.apply(null, arguments);
48
- }
49
- function _getPrototypeOf(t) {
50
- return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
51
- return t.__proto__ || Object.getPrototypeOf(t);
52
- }, _getPrototypeOf(t);
53
- }
54
- function _inherits(t, e) {
55
- if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function");
56
- t.prototype = Object.create(e && e.prototype, {
57
- constructor: {
58
- value: t,
59
- writable: !0,
60
- configurable: !0
61
- }
62
- }), Object.defineProperty(t, "prototype", {
63
- writable: !1
64
- }), e && _setPrototypeOf(t, e);
65
- }
66
- function _isNativeReflectConstruct() {
67
- try {
68
- var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
69
- } catch (t) {}
70
- return (_isNativeReflectConstruct = function () {
71
- return !!t;
72
- })();
73
- }
74
- function _iterableToArray(r) {
75
- if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
76
- }
77
- function _nonIterableSpread() {
78
- throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
79
- }
80
- function ownKeys$1(e, r) {
81
- var t = Object.keys(e);
82
- if (Object.getOwnPropertySymbols) {
83
- var o = Object.getOwnPropertySymbols(e);
84
- r && (o = o.filter(function (r) {
85
- return Object.getOwnPropertyDescriptor(e, r).enumerable;
86
- })), t.push.apply(t, o);
87
- }
88
- return t;
89
- }
90
- function _objectSpread2$1(e) {
91
- for (var r = 1; r < arguments.length; r++) {
92
- var t = null != arguments[r] ? arguments[r] : {};
93
- r % 2 ? ownKeys$1(Object(t), !0).forEach(function (r) {
94
- _defineProperty$1(e, r, t[r]);
95
- }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1(Object(t)).forEach(function (r) {
96
- Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
97
- });
98
- }
99
- return e;
100
- }
101
- function _possibleConstructorReturn(t, e) {
102
- if (e && ("object" == typeof e || "function" == typeof e)) return e;
103
- if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined");
104
- return _assertThisInitialized(t);
105
- }
106
- function _setPrototypeOf(t, e) {
107
- return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
108
- return t.__proto__ = e, t;
109
- }, _setPrototypeOf(t, e);
110
- }
111
- function _superPropBase(t, o) {
112
- for (; !{}.hasOwnProperty.call(t, o) && null !== (t = _getPrototypeOf(t)););
113
- return t;
114
- }
115
- function _superPropGet(t, o, e, r) {
116
- var p = _get(_getPrototypeOf(1 & r ? t.prototype : t), o, e);
117
- return 2 & r && "function" == typeof p ? function (t) {
118
- return p.apply(e, t);
119
- } : p;
120
- }
121
- function _toConsumableArray(r) {
122
- return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
123
- }
124
- function _toPrimitive$1(t, r) {
125
- if ("object" != typeof t || !t) return t;
126
- var e = t[Symbol.toPrimitive];
127
- if (void 0 !== e) {
128
- var i = e.call(t, r || "default");
129
- if ("object" != typeof i) return i;
130
- throw new TypeError("@@toPrimitive must return a primitive value.");
131
- }
132
- return ("string" === r ? String : Number)(t);
133
- }
134
- function _toPropertyKey$1(t) {
135
- var i = _toPrimitive$1(t, "string");
136
- return "symbol" == typeof i ? i : i + "";
137
- }
138
- function _unsupportedIterableToArray(r, a) {
139
- if (r) {
140
- if ("string" == typeof r) return _arrayLikeToArray(r, a);
141
- var t = {}.toString.call(r).slice(8, -1);
142
- return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
143
- }
144
- }
1
+ import { Events as Events$1, Utils, HTML5Video, Playback, Log, PlayerError } from '@clappr/core';
145
2
 
146
3
  // https://caniuse.com/mdn-javascript_builtins_number_isfinite
147
4
  const isFiniteNumber = Number.isFinite || function (value) {
@@ -36844,878 +36701,726 @@ class Hls {
36844
36701
  }
36845
36702
  Hls.defaultConfig = void 0;
36846
36703
 
36847
- var now = Utils.now,
36848
- listContainsIgnoreCase = Utils.listContainsIgnoreCase;
36849
- var AUTO = -1;
36850
- var DEFAULT_RECOVER_ATTEMPTS = 16;
36704
+ // Copyright 2014 Globo.com Player authors. All rights reserved.
36705
+ // Use of this source code is governed by a BSD-style
36706
+ // license that can be found in the LICENSE file.
36707
+
36708
+ const {
36709
+ now,
36710
+ listContainsIgnoreCase
36711
+ } = Utils;
36712
+ const AUTO = -1;
36713
+ const DEFAULT_RECOVER_ATTEMPTS = 16;
36851
36714
  Events$1.register('PLAYBACK_FRAGMENT_CHANGED');
36852
36715
  Events$1.register('PLAYBACK_FRAGMENT_PARSING_METADATA');
36853
- var HlsjsPlayback = /*#__PURE__*/function (_HTML5Video) {
36854
- function HlsjsPlayback() {
36855
- var _this;
36856
- _classCallCheck(this, HlsjsPlayback);
36857
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
36858
- args[_key] = arguments[_key];
36859
- }
36860
- _this = _callSuper(this, HlsjsPlayback, [].concat(args));
36861
- _this.options.hlsPlayback = _objectSpread2$1(_objectSpread2$1({}, _this.defaultOptions), _this.options.hlsPlayback);
36862
- _this._timeUpdateThrottleDelay = 200;
36863
- _this._timeUpdateFiringRate = 0.2;
36864
- _this._durationChangeMinOffset = 0.5;
36865
- _this._setInitialState();
36866
- return _this;
36867
- }
36868
- _inherits(HlsjsPlayback, _HTML5Video);
36869
- return _createClass(HlsjsPlayback, [{
36870
- key: "name",
36871
- get: function get() {
36872
- return 'hls';
36873
- }
36874
- }, {
36875
- key: "supportedVersion",
36876
- get: function get() {
36877
- return {
36878
- min: "0.14.6"
36879
- };
36880
- }
36881
- }, {
36882
- key: "levels",
36883
- get: function get() {
36884
- return this._levels || [];
36885
- }
36886
- }, {
36887
- key: "currentLevel",
36888
- get: function get() {
36889
- if (this._currentLevel === null || this._currentLevel === undefined) {
36890
- return AUTO;
36891
- } else {
36892
- return this._currentLevel;
36893
- } // 0 is a valid level ID
36894
- },
36895
- set: function set(id) {
36896
- this._currentLevel = id;
36897
- this.trigger(Events$1.PLAYBACK_LEVEL_SWITCH_START);
36898
- if (this.options.playback.hlsUseNextLevel) {
36899
- this._hls.nextLevel = this._currentLevel;
36900
- } else {
36901
- this._hls.currentLevel = this._currentLevel;
36902
- }
36903
- }
36904
- }, {
36905
- key: "isReady",
36906
- get: function get() {
36907
- return this._isReadyState;
36908
- }
36909
- }, {
36910
- key: "latency",
36911
- get: function get() {
36912
- return this._hls.latency;
36913
- }
36914
- }, {
36915
- key: "liveSyncPosition",
36916
- get: function get() {
36917
- return this._hls.liveSyncPosition;
36918
- }
36919
- }, {
36920
- key: "currentProgramDateTime",
36921
- get: function get() {
36922
- return this._hls.playingDate;
36923
- }
36924
- }, {
36925
- key: "_startTime",
36926
- get: function get() {
36927
- if (this._playbackType === Playback.LIVE && this._playlistType !== 'EVENT') {
36928
- return this._extrapolatedStartTime;
36929
- }
36930
- return this._playableRegionStartTime;
36931
- }
36932
- }, {
36933
- key: "_now",
36934
- get: function get() {
36935
- return now();
36936
- }
36937
-
36938
- // the time in the video element which should represent the start of the sliding window
36939
- // extrapolated to increase in real time (instead of jumping as the early segments are removed)
36940
- }, {
36941
- key: "_extrapolatedStartTime",
36942
- get: function get() {
36943
- if (!this._localStartTimeCorrelation) {
36944
- return this._playableRegionStartTime;
36945
- }
36946
- var corr = this._localStartTimeCorrelation;
36947
- var timePassed = this._now - corr.local;
36948
- var extrapolatedWindowStartTime = (corr.remote + timePassed) / 1000;
36949
- // cap at the end of the extrapolated window duration
36950
- return Math.min(extrapolatedWindowStartTime, this._playableRegionStartTime + this._extrapolatedWindowDuration);
36951
- }
36952
-
36953
- // the time in the video element which should represent the end of the content
36954
- // extrapolated to increase in real time (instead of jumping as segments are added)
36955
- }, {
36956
- key: "_extrapolatedEndTime",
36957
- get: function get() {
36958
- var actualEndTime = this._playableRegionStartTime + this._playableRegionDuration;
36959
- if (!this._localEndTimeCorrelation) return actualEndTime;
36960
- var correlation = this._localEndTimeCorrelation;
36961
- var timePassed = this._now - correlation.local;
36962
- var extrapolatedEndTime = (correlation.remote + timePassed) / 1000;
36963
- return Math.max(actualEndTime - this._extrapolatedWindowDuration, Math.min(extrapolatedEndTime, actualEndTime));
36716
+ class HlsjsPlayback extends HTML5Video {
36717
+ get name() {
36718
+ return 'hls';
36719
+ }
36720
+ get supportedVersion() {
36721
+ return {
36722
+ min: "0.14.7"
36723
+ };
36724
+ }
36725
+ get levels() {
36726
+ return this._levels || [];
36727
+ }
36728
+ get currentLevel() {
36729
+ if (this._currentLevel === null || this._currentLevel === undefined) {
36730
+ return AUTO;
36731
+ } else {
36732
+ return this._currentLevel;
36733
+ } // 0 is a valid level ID
36734
+ }
36735
+ get isReady() {
36736
+ return this._isReadyState;
36737
+ }
36738
+ set currentLevel(id) {
36739
+ this._currentLevel = id;
36740
+ this.trigger(Events$1.PLAYBACK_LEVEL_SWITCH_START);
36741
+ if (this.options.playback.hlsUseNextLevel) {
36742
+ this._hls.nextLevel = this._currentLevel;
36743
+ } else {
36744
+ this._hls.currentLevel = this._currentLevel;
36964
36745
  }
36965
- }, {
36966
- key: "_duration",
36967
- get: function get() {
36968
- return this._extrapolatedEndTime - this._startTime;
36746
+ }
36747
+ get latency() {
36748
+ return this._hls.latency;
36749
+ }
36750
+ get liveSyncPosition() {
36751
+ return this._hls.liveSyncPosition;
36752
+ }
36753
+ get currentProgramDateTime() {
36754
+ return this._hls.playingDate;
36755
+ }
36756
+ get _startTime() {
36757
+ if (this._playbackType === Playback.LIVE && this._playlistType !== 'EVENT') {
36758
+ return this._extrapolatedStartTime;
36969
36759
  }
36760
+ return this._playableRegionStartTime;
36761
+ }
36762
+ get _now() {
36763
+ return now();
36764
+ }
36970
36765
 
36971
- // Returns the duration (seconds) of the window that the extrapolated start time is allowed
36972
- // to move in before being capped.
36973
- // The extrapolated start time should never reach the cap at the end of the window as the
36974
- // window should slide as chunks are removed from the start.
36975
- // This also applies to the extrapolated end time in the same way.
36976
- //
36977
- // If chunks aren't being removed for some reason that the start time will reach and remain fixed at
36978
- // playableRegionStartTime + extrapolatedWindowDuration
36979
- //
36980
- // <-- window duration -->
36981
- // I.e playableRegionStartTime |-----------------------|
36982
- // | --> . . .
36983
- // . --> | --> . .
36984
- // . . --> | --> .
36985
- // . . . --> |
36986
- // . . . .
36987
- // extrapolatedStartTime
36988
- }, {
36989
- key: "_extrapolatedWindowDuration",
36990
- get: function get() {
36991
- if (this._segmentTargetDuration === null) {
36992
- return 0;
36993
- }
36994
- return this._extrapolatedWindowNumSegments * this._segmentTargetDuration;
36995
- }
36996
- }, {
36997
- key: "bandwidthEstimate",
36998
- get: function get() {
36999
- return this._hls && this._hls.bandwidthEstimate;
37000
- }
37001
- }, {
37002
- key: "defaultOptions",
37003
- get: function get() {
37004
- return {
37005
- preload: true
37006
- };
37007
- }
37008
- }, {
37009
- key: "customListeners",
37010
- get: function get() {
37011
- return this.options.hlsPlayback && this.options.hlsPlayback.customListeners || [];
37012
- }
37013
- }, {
37014
- key: "sourceMedia",
37015
- get: function get() {
37016
- return this.options.src;
37017
- }
37018
- }, {
37019
- key: "currentTimestamp",
37020
- get: function get() {
37021
- if (!this._currentFragment) return null;
37022
- var startTime = this._currentFragment.programDateTime;
37023
- var playbackTime = this.el.currentTime;
37024
- var playTimeOffSet = playbackTime - this._currentFragment.start;
37025
- var currentTimestampInMs = startTime + playTimeOffSet * 1000;
37026
- return currentTimestampInMs / 1000;
37027
- }
37028
- }, {
37029
- key: "_setInitialState",
37030
- value: function _setInitialState() {
37031
- this._minDvrSize = typeof this.options.hlsMinimumDvrSize === 'undefined' ? 60 : this.options.hlsMinimumDvrSize;
37032
- // The size of the start time extrapolation window measured as a multiple of segments.
37033
- // Should be 2 or higher, or 0 to disable. Should only need to be increased above 2 if more than one segment is
37034
- // removed from the start of the playlist at a time. E.g if the playlist is cached for 10 seconds and new chunks are
37035
- // added/removed every 5.
37036
- this._extrapolatedWindowNumSegments = !this.options.playback || typeof this.options.playback.extrapolatedWindowNumSegments === 'undefined' ? 2 : this.options.playback.extrapolatedWindowNumSegments;
37037
- this._playbackType = Playback.VOD;
37038
- this._lastTimeUpdate = {
37039
- current: 0,
37040
- total: 0,
37041
- firstFragDateTime: 0
37042
- };
37043
- this._lastTimeUpdateFiredTime = 0;
37044
- this._lastDuration = null;
37045
- // for hls streams which have dvr with a sliding window,
37046
- // the content at the start of the playlist is removed as new
37047
- // content is appended at the end.
37048
- // this means the actual playable start time will increase as the
37049
- // start content is deleted
37050
- // For streams with dvr where the entire recording is kept from the
37051
- // beginning this should stay as 0
37052
- this._playableRegionStartTime = 0;
37053
- // {local, remote} remote is the time in the video element that should represent 0
37054
- // local is the system time when the 'remote' measurment took place
37055
- this._localStartTimeCorrelation = null;
37056
- // {local, remote} remote is the time in the video element that should represents the end
37057
- // local is the system time when the 'remote' measurment took place
37058
- this._localEndTimeCorrelation = null;
37059
- // if content is removed from the beginning then this empty area should
37060
- // be ignored. "playableRegionDuration" excludes the empty area
37061
- this._playableRegionDuration = 0;
37062
- // #EXT-X-PROGRAM-DATE-TIME
37063
- this._programDateTime = 0;
37064
- // true when the actual duration is longer than hlsjs's live sync point
37065
- // when this is false playableRegionDuration will be the actual duration
37066
- // when this is true playableRegionDuration will exclude the time after the sync point
37067
- this._durationExcludesAfterLiveSyncPoint = false;
37068
- // #EXT-X-TARGETDURATION
37069
- this._segmentTargetDuration = null;
37070
- // #EXT-X-PLAYLIST-TYPE
37071
- this._playlistType = null;
37072
- this._recoverAttemptsRemaining = this.options.hlsRecoverAttempts || DEFAULT_RECOVER_ATTEMPTS;
37073
- }
37074
- }, {
37075
- key: "_setup",
37076
- value: function _setup() {
37077
- this._destroyHLSInstance();
37078
- this._createHLSInstance();
37079
- this._listenHLSEvents();
37080
- this._attachHLSMedia();
37081
- }
37082
- }, {
37083
- key: "_destroyHLSInstance",
37084
- value: function _destroyHLSInstance() {
37085
- if (!this._hls) return;
37086
- this._manifestLoading = false;
37087
- this._ccIsSetup = false;
37088
- this._ccTracksUpdated = false;
37089
- this._setInitialState();
37090
- this._hls.destroy();
37091
- this._hls = null;
37092
- }
37093
- }, {
37094
- key: "_createHLSInstance",
37095
- value: function _createHLSInstance() {
37096
- var config = _objectSpread2$1({}, this.options.playback.hlsjsConfig);
37097
- this._hls = new Hls(config);
37098
- }
37099
- }, {
37100
- key: "_attachHLSMedia",
37101
- value: function _attachHLSMedia() {
37102
- if (!this._hls) return;
37103
- this._hls.attachMedia(this.el);
37104
- }
37105
- }, {
37106
- key: "_listenHLSEvents",
37107
- value: function _listenHLSEvents() {
37108
- var _this2 = this;
37109
- if (!this._hls) return;
37110
- this._hls.once(Hls.Events.MEDIA_ATTACHED, function () {
37111
- _this2.options.hlsPlayback.preload && _this2._hls.loadSource(_this2.options.src);
37112
- });
37113
- this._hls.on(Hls.Events.MANIFEST_LOADING, function () {
37114
- _this2._manifestLoading = true;
37115
- });
37116
- this._hls.on(Hls.Events.LEVEL_LOADED, function (evt, data) {
37117
- return _this2._updatePlaybackType(evt, data);
37118
- });
37119
- this._hls.on(Hls.Events.LEVEL_UPDATED, function (evt, data) {
37120
- return _this2._onLevelUpdated(evt, data);
37121
- });
37122
- this._hls.on(Hls.Events.LEVEL_SWITCHED, function (evt, data) {
37123
- return _this2._onLevelSwitch(evt, data);
37124
- });
37125
- this._hls.on(Hls.Events.FRAG_CHANGED, function (evt, data) {
37126
- return _this2._onFragmentChanged(evt, data);
37127
- });
37128
- this._hls.on(Hls.Events.FRAG_LOADED, function (evt, data) {
37129
- return _this2._onFragmentLoaded(evt, data);
37130
- });
37131
- this._hls.on(Hls.Events.FRAG_BUFFERED, function (evt, data) {
37132
- return _this2._onFragmentBuffered(evt, data);
37133
- });
37134
- this._hls.on(Hls.Events.FRAG_PARSING_METADATA, function (evt, data) {
37135
- return _this2._onFragmentParsingMetadata(evt, data);
37136
- });
37137
- this._hls.on(Hls.Events.ERROR, function (evt, data) {
37138
- return _this2._onHLSJSError(evt, data);
37139
- });
37140
- this._hls.on(Hls.Events.SUBTITLE_TRACK_LOADED, function (evt, data) {
37141
- return _this2._onSubtitleLoaded(evt, data);
37142
- });
37143
- this._hls.on(Hls.Events.SUBTITLE_TRACKS_UPDATED, function () {
37144
- return _this2._ccTracksUpdated = true;
37145
- });
37146
- this.bindCustomListeners();
37147
- }
37148
- }, {
37149
- key: "bindCustomListeners",
37150
- value: function bindCustomListeners() {
37151
- var _this3 = this;
37152
- this.customListeners.forEach(function (item) {
37153
- var requestedEventName = item.eventName;
37154
- var typeOfListener = item.once ? 'once' : 'on';
37155
- requestedEventName && _this3._hls["".concat(typeOfListener)](requestedEventName, item.callback);
37156
- });
36766
+ // the time in the video element which should represent the start of the sliding window
36767
+ // extrapolated to increase in real time (instead of jumping as the early segments are removed)
36768
+ get _extrapolatedStartTime() {
36769
+ if (!this._localStartTimeCorrelation) {
36770
+ return this._playableRegionStartTime;
37157
36771
  }
37158
- }, {
37159
- key: "unbindCustomListeners",
37160
- value: function unbindCustomListeners() {
37161
- var _this4 = this;
37162
- this.customListeners.forEach(function (item) {
37163
- var requestedEventName = item.eventName;
37164
- requestedEventName && _this4._hls.off(requestedEventName, item.callback);
37165
- });
36772
+ const corr = this._localStartTimeCorrelation;
36773
+ const timePassed = this._now - corr.local;
36774
+ const extrapolatedWindowStartTime = (corr.remote + timePassed) / 1000;
36775
+ // cap at the end of the extrapolated window duration
36776
+ return Math.min(extrapolatedWindowStartTime, this._playableRegionStartTime + this._extrapolatedWindowDuration);
36777
+ }
36778
+
36779
+ // the time in the video element which should represent the end of the content
36780
+ // extrapolated to increase in real time (instead of jumping as segments are added)
36781
+ get _extrapolatedEndTime() {
36782
+ const actualEndTime = this._playableRegionStartTime + this._playableRegionDuration;
36783
+ if (!this._localEndTimeCorrelation) return actualEndTime;
36784
+ const correlation = this._localEndTimeCorrelation;
36785
+ const timePassed = this._now - correlation.local;
36786
+ const extrapolatedEndTime = (correlation.remote + timePassed) / 1000;
36787
+ return Math.max(actualEndTime - this._extrapolatedWindowDuration, Math.min(extrapolatedEndTime, actualEndTime));
36788
+ }
36789
+ get _duration() {
36790
+ return this._extrapolatedEndTime - this._startTime;
36791
+ }
36792
+
36793
+ // Returns the duration (seconds) of the window that the extrapolated start time is allowed
36794
+ // to move in before being capped.
36795
+ // The extrapolated start time should never reach the cap at the end of the window as the
36796
+ // window should slide as chunks are removed from the start.
36797
+ // This also applies to the extrapolated end time in the same way.
36798
+ //
36799
+ // If chunks aren't being removed for some reason that the start time will reach and remain fixed at
36800
+ // playableRegionStartTime + extrapolatedWindowDuration
36801
+ //
36802
+ // <-- window duration -->
36803
+ // I.e playableRegionStartTime |-----------------------|
36804
+ // | --> . . .
36805
+ // . --> | --> . .
36806
+ // . . --> | --> .
36807
+ // . . . --> |
36808
+ // . . . .
36809
+ // extrapolatedStartTime
36810
+ get _extrapolatedWindowDuration() {
36811
+ if (this._segmentTargetDuration === null) {
36812
+ return 0;
37166
36813
  }
37167
- }, {
37168
- key: "_onFragmentParsingMetadata",
37169
- value: function _onFragmentParsingMetadata(evt, data) {
37170
- this.trigger(Events$1.Custom.PLAYBACK_FRAGMENT_PARSING_METADATA, {
37171
- evt: evt,
37172
- data: data
36814
+ return this._extrapolatedWindowNumSegments * this._segmentTargetDuration;
36815
+ }
36816
+ get bandwidthEstimate() {
36817
+ return this._hls && this._hls.bandwidthEstimate;
36818
+ }
36819
+ get defaultOptions() {
36820
+ return {
36821
+ preload: true
36822
+ };
36823
+ }
36824
+ get customListeners() {
36825
+ return this.options.hlsPlayback && this.options.hlsPlayback.customListeners || [];
36826
+ }
36827
+ get sourceMedia() {
36828
+ return this.options.src;
36829
+ }
36830
+ get currentTimestamp() {
36831
+ if (!this._currentFragment) return null;
36832
+ const startTime = this._currentFragment.programDateTime;
36833
+ const playbackTime = this.el.currentTime;
36834
+ const playTimeOffSet = playbackTime - this._currentFragment.start;
36835
+ const currentTimestampInMs = startTime + playTimeOffSet * 1000;
36836
+ return currentTimestampInMs / 1000;
36837
+ }
36838
+ static get HLSJS() {
36839
+ return Hls;
36840
+ }
36841
+ constructor(...args) {
36842
+ super(...args);
36843
+ this.options.hlsPlayback = {
36844
+ ...this.defaultOptions,
36845
+ ...this.options.hlsPlayback
36846
+ };
36847
+ this._timeUpdateThrottleDelay = 200;
36848
+ this._timeUpdateFiringRate = 0.2;
36849
+ this._durationChangeMinOffset = 0.5;
36850
+ this._setInitialState();
36851
+ }
36852
+ _setInitialState() {
36853
+ this._minDvrSize = typeof this.options.hlsMinimumDvrSize === 'undefined' ? 60 : this.options.hlsMinimumDvrSize;
36854
+ // The size of the start time extrapolation window measured as a multiple of segments.
36855
+ // Should be 2 or higher, or 0 to disable. Should only need to be increased above 2 if more than one segment is
36856
+ // removed from the start of the playlist at a time. E.g if the playlist is cached for 10 seconds and new chunks are
36857
+ // added/removed every 5.
36858
+ this._extrapolatedWindowNumSegments = !this.options.playback || typeof this.options.playback.extrapolatedWindowNumSegments === 'undefined' ? 2 : this.options.playback.extrapolatedWindowNumSegments;
36859
+ this._playbackType = Playback.VOD;
36860
+ this._lastTimeUpdate = {
36861
+ current: 0,
36862
+ total: 0,
36863
+ firstFragDateTime: 0
36864
+ };
36865
+ this._lastTimeUpdateFiredTime = 0;
36866
+ this._lastDuration = null;
36867
+ // for hls streams which have dvr with a sliding window,
36868
+ // the content at the start of the playlist is removed as new
36869
+ // content is appended at the end.
36870
+ // this means the actual playable start time will increase as the
36871
+ // start content is deleted
36872
+ // For streams with dvr where the entire recording is kept from the
36873
+ // beginning this should stay as 0
36874
+ this._playableRegionStartTime = 0;
36875
+ // {local, remote} remote is the time in the video element that should represent 0
36876
+ // local is the system time when the 'remote' measurment took place
36877
+ this._localStartTimeCorrelation = null;
36878
+ // {local, remote} remote is the time in the video element that should represents the end
36879
+ // local is the system time when the 'remote' measurment took place
36880
+ this._localEndTimeCorrelation = null;
36881
+ // if content is removed from the beginning then this empty area should
36882
+ // be ignored. "playableRegionDuration" excludes the empty area
36883
+ this._playableRegionDuration = 0;
36884
+ // #EXT-X-PROGRAM-DATE-TIME
36885
+ this._programDateTime = 0;
36886
+ // true when the actual duration is longer than hlsjs's live sync point
36887
+ // when this is false playableRegionDuration will be the actual duration
36888
+ // when this is true playableRegionDuration will exclude the time after the sync point
36889
+ this._durationExcludesAfterLiveSyncPoint = false;
36890
+ // #EXT-X-TARGETDURATION
36891
+ this._segmentTargetDuration = null;
36892
+ // #EXT-X-PLAYLIST-TYPE
36893
+ this._playlistType = null;
36894
+ this._recoverAttemptsRemaining = this.options.hlsRecoverAttempts || DEFAULT_RECOVER_ATTEMPTS;
36895
+ }
36896
+ _setup() {
36897
+ this._destroyHLSInstance();
36898
+ this._createHLSInstance();
36899
+ this._listenHLSEvents();
36900
+ this._attachHLSMedia();
36901
+ }
36902
+ _destroyHLSInstance() {
36903
+ if (!this._hls) return;
36904
+ this._manifestLoading = false;
36905
+ this._ccIsSetup = false;
36906
+ this._ccTracksUpdated = false;
36907
+ this._setInitialState();
36908
+ this._hls.destroy();
36909
+ this._hls = null;
36910
+ }
36911
+ _createHLSInstance() {
36912
+ const config = {
36913
+ ...this.options.playback.hlsjsConfig
36914
+ };
36915
+ this._hls = new Hls(config);
36916
+ }
36917
+ _attachHLSMedia() {
36918
+ if (!this._hls) return;
36919
+ this._hls.attachMedia(this.el);
36920
+ }
36921
+ _listenHLSEvents() {
36922
+ if (!this._hls) return;
36923
+ this._hls.once(Hls.Events.MEDIA_ATTACHED, () => {
36924
+ this.options.hlsPlayback.preload && this._hls.loadSource(this.options.src);
36925
+ });
36926
+ this._hls.on(Hls.Events.MANIFEST_LOADING, () => {
36927
+ this._manifestLoading = true;
36928
+ });
36929
+ this._hls.on(Hls.Events.LEVEL_LOADED, (evt, data) => this._updatePlaybackType(evt, data));
36930
+ this._hls.on(Hls.Events.LEVEL_UPDATED, (evt, data) => this._onLevelUpdated(evt, data));
36931
+ this._hls.on(Hls.Events.LEVEL_SWITCHED, (evt, data) => this._onLevelSwitch(evt, data));
36932
+ this._hls.on(Hls.Events.FRAG_CHANGED, (evt, data) => this._onFragmentChanged(evt, data));
36933
+ this._hls.on(Hls.Events.FRAG_LOADED, (evt, data) => this._onFragmentLoaded(evt, data));
36934
+ this._hls.on(Hls.Events.FRAG_BUFFERED, (evt, data) => this._onFragmentBuffered(evt, data));
36935
+ this._hls.on(Hls.Events.FRAG_PARSING_METADATA, (evt, data) => this._onFragmentParsingMetadata(evt, data));
36936
+ this._hls.on(Hls.Events.ERROR, (evt, data) => this._onHLSJSError(evt, data));
36937
+ this._hls.on(Hls.Events.SUBTITLE_TRACK_LOADED, (evt, data) => this._onSubtitleLoaded(evt, data));
36938
+ this._hls.on(Hls.Events.SUBTITLE_TRACKS_UPDATED, () => this._ccTracksUpdated = true);
36939
+ this.bindCustomListeners();
36940
+ }
36941
+ bindCustomListeners() {
36942
+ this.customListeners.forEach(item => {
36943
+ const requestedEventName = item.eventName;
36944
+ const typeOfListener = item.once ? 'once' : 'on';
36945
+ requestedEventName && this._hls[`${typeOfListener}`](requestedEventName, item.callback);
36946
+ });
36947
+ }
36948
+ unbindCustomListeners() {
36949
+ this.customListeners.forEach(item => {
36950
+ const requestedEventName = item.eventName;
36951
+ requestedEventName && this._hls.off(requestedEventName, item.callback);
36952
+ });
36953
+ }
36954
+ _onFragmentParsingMetadata(evt, data) {
36955
+ this.trigger(Events$1.Custom.PLAYBACK_FRAGMENT_PARSING_METADATA, {
36956
+ evt,
36957
+ data
36958
+ });
36959
+ }
36960
+ render() {
36961
+ this._ready();
36962
+ return super.render();
36963
+ }
36964
+ _ready() {
36965
+ if (this._isReadyState) return;
36966
+ !this._hls && this._setup();
36967
+ this._isReadyState = true;
36968
+ this.trigger(Events$1.PLAYBACK_READY, this.name);
36969
+ }
36970
+ _recover(evt, data, error) {
36971
+ if (!this._recoveredDecodingError) {
36972
+ this._recoveredDecodingError = true;
36973
+ this._hls.recoverMediaError();
36974
+ this.play();
36975
+ } else if (!this._recoveredAudioCodecError) {
36976
+ this._recoveredAudioCodecError = true;
36977
+ this._hls.swapAudioCodec();
36978
+ this._hls.recoverMediaError();
36979
+ this.play();
36980
+ } else {
36981
+ Log.error('hlsjs: failed to recover', {
36982
+ evt,
36983
+ data
37173
36984
  });
36985
+ error.level = PlayerError.Levels.FATAL;
36986
+ const formattedError = this.createError(error);
36987
+ this.trigger(Events$1.PLAYBACK_ERROR, formattedError);
36988
+ this.stop();
37174
36989
  }
37175
- }, {
37176
- key: "render",
37177
- value: function render() {
37178
- this._ready();
37179
- return _superPropGet(HlsjsPlayback, "render", this, 3)([]);
37180
- }
37181
- }, {
37182
- key: "_ready",
37183
- value: function _ready() {
37184
- if (this._isReadyState) return;
37185
- !this._hls && this._setup();
37186
- this._isReadyState = true;
37187
- this.trigger(Events$1.PLAYBACK_READY, this.name);
37188
- }
37189
- }, {
37190
- key: "_recover",
37191
- value: function _recover(evt, data, error) {
37192
- if (!this._recoveredDecodingError) {
37193
- this._recoveredDecodingError = true;
37194
- this._hls.recoverMediaError();
37195
- this.play();
37196
- } else if (!this._recoveredAudioCodecError) {
37197
- this._recoveredAudioCodecError = true;
37198
- this._hls.swapAudioCodec();
37199
- this._hls.recoverMediaError();
37200
- this.play();
37201
- } else {
37202
- Log.error('hlsjs: failed to recover', {
37203
- evt: evt,
37204
- data: data
37205
- });
37206
- error.level = PlayerError.Levels.FATAL;
37207
- var formattedError = this.createError(error);
37208
- this.trigger(Events$1.PLAYBACK_ERROR, formattedError);
37209
- this.stop();
37210
- }
37211
- }
36990
+ }
37212
36991
 
37213
- // override
37214
- // this playback manages the src on the video element itself
37215
- }, {
37216
- key: "_setupSrc",
37217
- value: function _setupSrc(srcUrl) {} // eslint-disable-line no-unused-vars
37218
- }, {
37219
- key: "_startTimeUpdateTimer",
37220
- value: function _startTimeUpdateTimer() {
37221
- var _this5 = this;
37222
- if (this._timeUpdateTimer) return;
37223
- this._timeUpdateTimer = setInterval(function () {
37224
- _this5._onDurationChange();
37225
- _this5._onTimeUpdate();
37226
- }, 100);
37227
- }
37228
- }, {
37229
- key: "_stopTimeUpdateTimer",
37230
- value: function _stopTimeUpdateTimer() {
37231
- if (!this._timeUpdateTimer) return;
37232
- clearInterval(this._timeUpdateTimer);
37233
- this._timeUpdateTimer = null;
37234
- }
37235
- }, {
37236
- key: "getProgramDateTime",
37237
- value: function getProgramDateTime() {
37238
- return this._programDateTime;
37239
- }
36992
+ // override
36993
+ // this playback manages the src on the video element itself
36994
+ _setupSrc(srcUrl) {} // eslint-disable-line no-unused-vars
37240
36995
 
37241
- // the duration on the video element itself should not be used
37242
- // as this does not necesarily represent the duration of the stream
37243
- // https://github.com/clappr/clappr/issues/668#issuecomment-157036678
37244
- }, {
37245
- key: "getDuration",
37246
- value: function getDuration() {
37247
- return this._duration;
37248
- }
36996
+ _startTimeUpdateTimer() {
36997
+ if (this._timeUpdateTimer) return;
36998
+ this._timeUpdateTimer = setInterval(() => {
36999
+ this._onDurationChange();
37000
+ this._onTimeUpdate();
37001
+ }, 100);
37002
+ }
37003
+ _stopTimeUpdateTimer() {
37004
+ if (!this._timeUpdateTimer) return;
37005
+ clearInterval(this._timeUpdateTimer);
37006
+ this._timeUpdateTimer = null;
37007
+ }
37008
+ getProgramDateTime() {
37009
+ return this._programDateTime;
37010
+ }
37249
37011
 
37250
- // the frame rate should be retrieved from the HLS.js level information
37251
- // as it is not necessarily exposed directly by the video element
37252
- }, {
37253
- key: "getFrameRate",
37254
- value: function getFrameRate() {
37255
- if (this._hls && this._hls.levels && this._hls.currentLevel >= 0) {
37256
- var level = this._hls.levels[this._hls.currentLevel];
37257
- return level && level.frameRate ? level.frameRate : null;
37258
- }
37259
- return null;
37260
- }
37261
- }, {
37262
- key: "getCurrentTime",
37263
- value: function getCurrentTime() {
37264
- // e.g. can be < 0 if user pauses near the start
37265
- // eventually they will then be kicked to the end by hlsjs if they run out of buffer
37266
- // before the official start time
37267
- return Math.max(0, this.el.currentTime - this._startTime);
37268
- }
37012
+ // the duration on the video element itself should not be used
37013
+ // as this does not necesarily represent the duration of the stream
37014
+ // https://github.com/clappr/clappr/issues/668#issuecomment-157036678
37015
+ getDuration() {
37016
+ return this._duration;
37017
+ }
37269
37018
 
37270
- // the time that "0" now represents relative to when playback started
37271
- // for a stream with a sliding window this will increase as content is
37272
- // removed from the beginning
37273
- }, {
37274
- key: "getStartTimeOffset",
37275
- value: function getStartTimeOffset() {
37276
- return this._startTime;
37277
- }
37278
- }, {
37279
- key: "seekPercentage",
37280
- value: function seekPercentage(percentage) {
37281
- var seekTo = percentage > 0 ? this._duration * (percentage / 100) : this._duration;
37282
- this.seek(seekTo);
37019
+ // the frame rate should be retrieved from the HLS.js level information
37020
+ // as it is not necessarily exposed directly by the video element
37021
+ getFrameRate() {
37022
+ if (this._hls && this._hls.levels && this._hls.currentLevel >= 0) {
37023
+ const level = this._hls.levels[this._hls.currentLevel];
37024
+ return level && level.frameRate ? level.frameRate : null;
37283
37025
  }
37284
- }, {
37285
- key: "seek",
37286
- value: function seek(time) {
37287
- if (time < 0) {
37288
- Log.warn('Attempt to seek to a negative time. Resetting to live point. Use seekToLivePoint() to seek to the live point.');
37289
- time = this.getDuration();
37290
- }
37291
- time += this._startTime;
37292
- this.el.currentTime = time;
37293
- }
37294
- }, {
37295
- key: "seekToLivePoint",
37296
- value: function seekToLivePoint() {
37297
- this.seek(this.getDuration());
37026
+ return null;
37027
+ }
37028
+ getCurrentTime() {
37029
+ // e.g. can be < 0 if user pauses near the start
37030
+ // eventually they will then be kicked to the end by hlsjs if they run out of buffer
37031
+ // before the official start time
37032
+ return Math.max(0, this.el.currentTime - this._startTime);
37033
+ }
37034
+
37035
+ // the time that "0" now represents relative to when playback started
37036
+ // for a stream with a sliding window this will increase as content is
37037
+ // removed from the beginning
37038
+ getStartTimeOffset() {
37039
+ return this._startTime;
37040
+ }
37041
+ seekPercentage(percentage) {
37042
+ const seekTo = percentage > 0 ? this._duration * (percentage / 100) : this._duration;
37043
+ this.seek(seekTo);
37044
+ }
37045
+ seek(time) {
37046
+ if (time < 0) {
37047
+ Log.warn('Attempt to seek to a negative time. Resetting to live point. Use seekToLivePoint() to seek to the live point.');
37048
+ time = this.getDuration();
37298
37049
  }
37299
- }, {
37300
- key: "_updateSettings",
37301
- value: function _updateSettings() {
37302
- if (this._playbackType === Playback.VOD) {
37303
- this.settings.left = ['playpause', 'position', 'duration'];
37304
- } else if (this.dvrEnabled) {
37305
- this.settings.left = ['playpause'];
37306
- } else {
37307
- this.settings.left = ['playstop'];
37308
- }
37309
- this.settings.seekEnabled = this.isSeekEnabled();
37310
- this.trigger(Events$1.PLAYBACK_SETTINGSUPDATE);
37050
+ time += this._startTime;
37051
+ this.el.currentTime = time;
37052
+ }
37053
+ seekToLivePoint() {
37054
+ this.seek(this.getDuration());
37055
+ }
37056
+ _updateSettings() {
37057
+ if (this._playbackType === Playback.VOD) {
37058
+ this.settings.left = ['playpause', 'position', 'duration'];
37059
+ } else if (this.dvrEnabled) {
37060
+ this.settings.left = ['playpause'];
37061
+ } else {
37062
+ this.settings.left = ['playstop'];
37311
37063
  }
37312
- }, {
37313
- key: "_onHLSJSError",
37314
- value: function _onHLSJSError(evt, data) {
37315
- var error = {
37316
- code: "".concat(data.type, "_").concat(data.details),
37317
- description: "".concat(this.name, " error: type: ").concat(data.type, ", details: ").concat(data.details),
37318
- raw: data
37319
- };
37320
- var formattedError;
37321
- if (data.response) error.description += ", response: ".concat(JSON.stringify(data.response));
37322
- // only report/handle errors if they are fatal
37323
- // hlsjs should automatically handle non fatal errors
37324
- if (data.fatal) {
37325
- if (this._recoverAttemptsRemaining > 0) {
37326
- this._recoverAttemptsRemaining -= 1;
37327
- switch (data.type) {
37328
- case Hls.ErrorTypes.NETWORK_ERROR:
37329
- switch (data.details) {
37330
- // The following network errors cannot be recovered with HLS.startLoad()
37331
- // For more details, see https://github.com/video-dev/hls.js/blob/master/doc/design.md#error-detection-and-handling
37332
- // For "level load" fatal errors, see https://github.com/video-dev/hls.js/issues/1138
37333
- case Hls.ErrorDetails.MANIFEST_LOAD_ERROR:
37334
- case Hls.ErrorDetails.MANIFEST_LOAD_TIMEOUT:
37335
- case Hls.ErrorDetails.MANIFEST_PARSING_ERROR:
37336
- case Hls.ErrorDetails.LEVEL_LOAD_ERROR:
37337
- case Hls.ErrorDetails.LEVEL_LOAD_TIMEOUT:
37338
- Log.error('hlsjs: unrecoverable network fatal error.', {
37339
- evt: evt,
37340
- data: data
37341
- });
37342
- formattedError = this.createError(error);
37343
- this.trigger(Events$1.PLAYBACK_ERROR, formattedError);
37344
- this.stop();
37345
- break;
37346
- default:
37347
- Log.warn('hlsjs: trying to recover from network error.', {
37348
- evt: evt,
37349
- data: data
37350
- });
37351
- error.level = PlayerError.Levels.WARN;
37352
- this._hls.startLoad();
37353
- break;
37354
- }
37355
- break;
37356
- case Hls.ErrorTypes.MEDIA_ERROR:
37357
- Log.warn('hlsjs: trying to recover from media error.', {
37358
- evt: evt,
37359
- data: data
37360
- });
37361
- error.level = PlayerError.Levels.WARN;
37362
- this._recover(evt, data, error);
37363
- break;
37364
- default:
37365
- Log.error('hlsjs: could not recover from error.', {
37366
- evt: evt,
37367
- data: data
37368
- });
37369
- formattedError = this.createError(error);
37370
- this.trigger(Events$1.PLAYBACK_ERROR, formattedError);
37371
- this.stop();
37372
- break;
37373
- }
37374
- } else {
37375
- Log.error('hlsjs: could not recover from error after maximum number of attempts.', {
37376
- evt: evt,
37377
- data: data
37378
- });
37379
- formattedError = this.createError(error);
37380
- this.trigger(Events$1.PLAYBACK_ERROR, formattedError);
37381
- this.stop();
37064
+ this.settings.seekEnabled = this.isSeekEnabled();
37065
+ this.trigger(Events$1.PLAYBACK_SETTINGSUPDATE);
37066
+ }
37067
+ _onHLSJSError(evt, data) {
37068
+ const error = {
37069
+ code: `${data.type}_${data.details}`,
37070
+ description: `${this.name} error: type: ${data.type}, details: ${data.details}`,
37071
+ raw: data
37072
+ };
37073
+ let formattedError;
37074
+ if (data.response) error.description += `, response: ${JSON.stringify(data.response)}`;
37075
+ // only report/handle errors if they are fatal
37076
+ // hlsjs should automatically handle non fatal errors
37077
+ if (data.fatal) {
37078
+ if (this._recoverAttemptsRemaining > 0) {
37079
+ this._recoverAttemptsRemaining -= 1;
37080
+ switch (data.type) {
37081
+ case Hls.ErrorTypes.NETWORK_ERROR:
37082
+ switch (data.details) {
37083
+ // The following network errors cannot be recovered with HLS.startLoad()
37084
+ // For more details, see https://github.com/video-dev/hls.js/blob/master/doc/design.md#error-detection-and-handling
37085
+ // For "level load" fatal errors, see https://github.com/video-dev/hls.js/issues/1138
37086
+ case Hls.ErrorDetails.MANIFEST_LOAD_ERROR:
37087
+ case Hls.ErrorDetails.MANIFEST_LOAD_TIMEOUT:
37088
+ case Hls.ErrorDetails.MANIFEST_PARSING_ERROR:
37089
+ case Hls.ErrorDetails.LEVEL_LOAD_ERROR:
37090
+ case Hls.ErrorDetails.LEVEL_LOAD_TIMEOUT:
37091
+ Log.error('hlsjs: unrecoverable network fatal error.', {
37092
+ evt,
37093
+ data
37094
+ });
37095
+ formattedError = this.createError(error);
37096
+ this.trigger(Events$1.PLAYBACK_ERROR, formattedError);
37097
+ this.stop();
37098
+ break;
37099
+ default:
37100
+ Log.warn('hlsjs: trying to recover from network error.', {
37101
+ evt,
37102
+ data
37103
+ });
37104
+ error.level = PlayerError.Levels.WARN;
37105
+ this._hls.startLoad();
37106
+ break;
37107
+ }
37108
+ break;
37109
+ case Hls.ErrorTypes.MEDIA_ERROR:
37110
+ Log.warn('hlsjs: trying to recover from media error.', {
37111
+ evt,
37112
+ data
37113
+ });
37114
+ error.level = PlayerError.Levels.WARN;
37115
+ this._recover(evt, data, error);
37116
+ break;
37117
+ default:
37118
+ Log.error('hlsjs: could not recover from error.', {
37119
+ evt,
37120
+ data
37121
+ });
37122
+ formattedError = this.createError(error);
37123
+ this.trigger(Events$1.PLAYBACK_ERROR, formattedError);
37124
+ this.stop();
37125
+ break;
37382
37126
  }
37383
37127
  } else {
37384
- // Transforms HLSJS.ErrorDetails.KEY_LOAD_ERROR non-fatal error to
37385
- // playback fatal error if triggerFatalErrorOnResourceDenied playback
37386
- // option is set. HLSJS.ErrorTypes.KEY_SYSTEM_ERROR are fatal errors
37387
- // and therefore already handled.
37388
- if (this.options.playback.triggerFatalErrorOnResourceDenied && this._keyIsDenied(data)) {
37389
- Log.error('hlsjs: could not load decrypt key.', {
37390
- evt: evt,
37391
- data: data
37392
- });
37393
- formattedError = this.createError(error);
37394
- this.trigger(Events$1.PLAYBACK_ERROR, formattedError);
37395
- this.stop();
37396
- return;
37397
- }
37398
- error.level = PlayerError.Levels.WARN;
37399
- Log.warn('hlsjs: non-fatal error occurred', {
37400
- evt: evt,
37401
- data: data
37128
+ Log.error('hlsjs: could not recover from error after maximum number of attempts.', {
37129
+ evt,
37130
+ data
37402
37131
  });
37132
+ formattedError = this.createError(error);
37133
+ this.trigger(Events$1.PLAYBACK_ERROR, formattedError);
37134
+ this.stop();
37403
37135
  }
37136
+ } else {
37137
+ // Transforms HLSJS.ErrorDetails.KEY_LOAD_ERROR non-fatal error to
37138
+ // playback fatal error if triggerFatalErrorOnResourceDenied playback
37139
+ // option is set. HLSJS.ErrorTypes.KEY_SYSTEM_ERROR are fatal errors
37140
+ // and therefore already handled.
37141
+ if (this.options.playback.triggerFatalErrorOnResourceDenied && this._keyIsDenied(data)) {
37142
+ Log.error('hlsjs: could not load decrypt key.', {
37143
+ evt,
37144
+ data
37145
+ });
37146
+ formattedError = this.createError(error);
37147
+ this.trigger(Events$1.PLAYBACK_ERROR, formattedError);
37148
+ this.stop();
37149
+ return;
37150
+ }
37151
+ error.level = PlayerError.Levels.WARN;
37152
+ Log.warn('hlsjs: non-fatal error occurred', {
37153
+ evt,
37154
+ data
37155
+ });
37404
37156
  }
37405
- }, {
37406
- key: "_keyIsDenied",
37407
- value: function _keyIsDenied(data) {
37408
- return data.type === Hls.ErrorTypes.NETWORK_ERROR && data.details === Hls.ErrorDetails.KEY_LOAD_ERROR && data.response && data.response.code >= 400;
37409
- }
37410
- }, {
37411
- key: "_onTimeUpdate",
37412
- value: function _onTimeUpdate() {
37413
- var update = {
37414
- current: this.getCurrentTime(),
37415
- total: this.getDuration(),
37416
- firstFragDateTime: this.getProgramDateTime()
37417
- };
37418
- var shouldThrottle = this._shouldThrottleTimeUpdate(update);
37419
- if (shouldThrottle) return;
37420
- this._lastTimeUpdate = update;
37421
- this._lastTimeUpdateFiredTime = this._now;
37422
- this.trigger(Events$1.PLAYBACK_TIMEUPDATE, update, this.name);
37423
- }
37424
- }, {
37425
- key: "_shouldThrottleTimeUpdate",
37426
- value: function _shouldThrottleTimeUpdate(update) {
37427
- var isSameTime = Math.abs(update.current - this._lastTimeUpdate.current) < this._timeUpdateFiringRate;
37428
- var isSameDuration = Math.abs(update.total - this._lastTimeUpdate.total) < this._durationChangeMinOffset;
37429
- var isSameFirstFragDateTime = update.firstFragDateTime === this._lastTimeUpdate.firstFragDateTime;
37430
- var isSameEventPayload = isSameTime && isSameDuration && isSameFirstFragDateTime;
37431
- var isThrottled = this._now - this._lastTimeUpdateFiredTime < this._timeUpdateThrottleDelay;
37432
- return isSameEventPayload && isThrottled;
37433
- }
37434
- }, {
37435
- key: "_onDurationChange",
37436
- value: function _onDurationChange() {
37437
- var duration = this.getDuration();
37438
- var isSameDuration = Math.abs(this._lastDuration - duration) < this._durationChangeMinOffset;
37439
- if (isSameDuration) return;
37440
- this._lastDuration = duration;
37441
- _superPropGet(HlsjsPlayback, "_onDurationChange", this, 3)([]);
37157
+ }
37158
+ _keyIsDenied(data) {
37159
+ return data.type === Hls.ErrorTypes.NETWORK_ERROR && data.details === Hls.ErrorDetails.KEY_LOAD_ERROR && data.response && data.response.code >= 400;
37160
+ }
37161
+ _onTimeUpdate() {
37162
+ const update = {
37163
+ current: this.getCurrentTime(),
37164
+ total: this.getDuration(),
37165
+ firstFragDateTime: this.getProgramDateTime()
37166
+ };
37167
+ const shouldThrottle = this._shouldThrottleTimeUpdate(update);
37168
+ if (shouldThrottle) return;
37169
+ this._lastTimeUpdate = update;
37170
+ this._lastTimeUpdateFiredTime = this._now;
37171
+ this.trigger(Events$1.PLAYBACK_TIMEUPDATE, update, this.name);
37172
+ }
37173
+ _shouldThrottleTimeUpdate(update) {
37174
+ const isSameTime = Math.abs(update.current - this._lastTimeUpdate.current) < this._timeUpdateFiringRate;
37175
+ const isSameDuration = Math.abs(update.total - this._lastTimeUpdate.total) < this._durationChangeMinOffset;
37176
+ const isSameFirstFragDateTime = update.firstFragDateTime === this._lastTimeUpdate.firstFragDateTime;
37177
+ const isSameEventPayload = isSameTime && isSameDuration && isSameFirstFragDateTime;
37178
+ const isThrottled = this._now - this._lastTimeUpdateFiredTime < this._timeUpdateThrottleDelay;
37179
+ return isSameEventPayload && isThrottled;
37180
+ }
37181
+ _onDurationChange() {
37182
+ const duration = this.getDuration();
37183
+ const isSameDuration = Math.abs(this._lastDuration - duration) < this._durationChangeMinOffset;
37184
+ if (isSameDuration) return;
37185
+ this._lastDuration = duration;
37186
+ super._onDurationChange();
37187
+ }
37188
+ _onProgress() {
37189
+ if (!this.el.buffered.length) return;
37190
+ let buffered = [];
37191
+ let bufferedPos = 0;
37192
+ for (let i = 0; i < this.el.buffered.length; i++) {
37193
+ buffered = [...buffered, {
37194
+ // for a stream with sliding window dvr something that is buffered my slide off the start of the timeline
37195
+ start: Math.max(0, this.el.buffered.start(i) - this._playableRegionStartTime),
37196
+ end: Math.max(0, this.el.buffered.end(i) - this._playableRegionStartTime)
37197
+ }];
37198
+ if (this.el.currentTime >= buffered[i].start && this.el.currentTime <= buffered[i].end) {
37199
+ bufferedPos = i;
37200
+ }
37201
+ }
37202
+ const progress = {
37203
+ start: buffered[bufferedPos].start,
37204
+ current: buffered[bufferedPos].end,
37205
+ total: this.getDuration()
37206
+ };
37207
+ this.trigger(Events$1.PLAYBACK_PROGRESS, progress, buffered);
37208
+ }
37209
+ load(url) {
37210
+ this._stopTimeUpdateTimer();
37211
+ this.options.src = url;
37212
+ this._setup();
37213
+ }
37214
+ play() {
37215
+ !this._hls && this._setup();
37216
+ !this._manifestLoading && !this.options.hlsPlayback.preload && this._hls.loadSource(this.options.src);
37217
+ super.play();
37218
+ this._startTimeUpdateTimer();
37219
+ }
37220
+ pause() {
37221
+ if (!this._hls) return;
37222
+ this.el.pause();
37223
+ }
37224
+ stop() {
37225
+ this._stopTimeUpdateTimer();
37226
+ if (this._hls) super.stop();
37227
+ this._destroyHLSInstance();
37228
+ }
37229
+ destroy() {
37230
+ this._stopTimeUpdateTimer();
37231
+ this._destroyHLSInstance();
37232
+ super.destroy();
37233
+ }
37234
+ _updatePlaybackType(evt, data) {
37235
+ this._playbackType = data.details.live ? Playback.LIVE : Playback.VOD;
37236
+ this._onLevelUpdated(evt, data);
37237
+ // Live stream subtitle tracks detection hack (may not immediately available)
37238
+ if (this._ccTracksUpdated && this._playbackType === Playback.LIVE && this.hasClosedCaptionsTracks) {
37239
+ this._onSubtitleLoaded();
37442
37240
  }
37443
- }, {
37444
- key: "_onProgress",
37445
- value: function _onProgress() {
37446
- if (!this.el.buffered.length) return;
37447
- var buffered = [];
37448
- var bufferedPos = 0;
37449
- for (var i = 0; i < this.el.buffered.length; i++) {
37450
- buffered = [].concat(_toConsumableArray(buffered), [{
37451
- // for a stream with sliding window dvr something that is buffered my slide off the start of the timeline
37452
- start: Math.max(0, this.el.buffered.start(i) - this._playableRegionStartTime),
37453
- end: Math.max(0, this.el.buffered.end(i) - this._playableRegionStartTime)
37454
- }]);
37455
- if (this.el.currentTime >= buffered[i].start && this.el.currentTime <= buffered[i].end) {
37456
- bufferedPos = i;
37457
- }
37458
- }
37459
- var progress = {
37460
- start: buffered[bufferedPos].start,
37461
- current: buffered[bufferedPos].end,
37462
- total: this.getDuration()
37241
+ }
37242
+ _fillLevels() {
37243
+ this._levels = this._hls.levels.map((level, index) => {
37244
+ return {
37245
+ id: index,
37246
+ level: level,
37247
+ label: `${level.bitrate / 1000}Kbps`
37463
37248
  };
37464
- this.trigger(Events$1.PLAYBACK_PROGRESS, progress, buffered);
37465
- }
37466
- }, {
37467
- key: "load",
37468
- value: function load(url) {
37469
- this._stopTimeUpdateTimer();
37470
- this.options.src = url;
37471
- this._setup();
37472
- }
37473
- }, {
37474
- key: "play",
37475
- value: function play() {
37476
- !this._hls && this._setup();
37477
- !this._manifestLoading && !this.options.hlsPlayback.preload && this._hls.loadSource(this.options.src);
37478
- _superPropGet(HlsjsPlayback, "play", this, 3)([]);
37479
- this._startTimeUpdateTimer();
37480
- }
37481
- }, {
37482
- key: "pause",
37483
- value: function pause() {
37484
- if (!this._hls) return;
37485
- this.el.pause();
37486
- }
37487
- }, {
37488
- key: "stop",
37489
- value: function stop() {
37490
- this._stopTimeUpdateTimer();
37491
- if (this._hls) _superPropGet(HlsjsPlayback, "stop", this, 3)([]);
37492
- this._destroyHLSInstance();
37493
- }
37494
- }, {
37495
- key: "destroy",
37496
- value: function destroy() {
37497
- this._stopTimeUpdateTimer();
37498
- this._destroyHLSInstance();
37499
- _superPropGet(HlsjsPlayback, "destroy", this, 3)([]);
37500
- }
37501
- }, {
37502
- key: "_updatePlaybackType",
37503
- value: function _updatePlaybackType(evt, data) {
37504
- this._playbackType = data.details.live ? Playback.LIVE : Playback.VOD;
37505
- this._onLevelUpdated(evt, data);
37506
- // Live stream subtitle tracks detection hack (may not immediately available)
37507
- if (this._ccTracksUpdated && this._playbackType === Playback.LIVE && this.hasClosedCaptionsTracks) {
37508
- this._onSubtitleLoaded();
37509
- }
37510
- }
37511
- }, {
37512
- key: "_fillLevels",
37513
- value: function _fillLevels() {
37514
- this._levels = this._hls.levels.map(function (level, index) {
37515
- return {
37516
- id: index,
37517
- level: level,
37518
- label: "".concat(level.bitrate / 1000, "Kbps")
37249
+ });
37250
+ this.trigger(Events$1.PLAYBACK_LEVELS_AVAILABLE, this._levels);
37251
+ }
37252
+ _onLevelUpdated(evt, data) {
37253
+ this._segmentTargetDuration = data.details.targetduration;
37254
+ this._playlistType = data.details.type || null;
37255
+ let startTimeChanged = false;
37256
+ let durationChanged = false;
37257
+ const fragments = data.details.fragments;
37258
+ const previousPlayableRegionStartTime = this._playableRegionStartTime;
37259
+ const previousPlayableRegionDuration = this._playableRegionDuration;
37260
+ if (fragments.length === 0) return;
37261
+ // #EXT-X-PROGRAM-DATE-TIME
37262
+ if (fragments[0].rawProgramDateTime) {
37263
+ this._programDateTime = fragments[0].rawProgramDateTime;
37264
+ }
37265
+ if (this._playableRegionStartTime !== fragments[0].start) {
37266
+ startTimeChanged = true;
37267
+ this._playableRegionStartTime = fragments[0].start;
37268
+ }
37269
+ if (startTimeChanged) {
37270
+ if (!this._localStartTimeCorrelation) {
37271
+ // set the correlation to map to middle of the extrapolation window
37272
+ this._localStartTimeCorrelation = {
37273
+ local: this._now,
37274
+ remote: (fragments[0].start + this._extrapolatedWindowDuration / 2) * 1000
37519
37275
  };
37520
- });
37521
- this.trigger(Events$1.PLAYBACK_LEVELS_AVAILABLE, this._levels);
37522
- }
37523
- }, {
37524
- key: "_onLevelUpdated",
37525
- value: function _onLevelUpdated(evt, data) {
37526
- this._segmentTargetDuration = data.details.targetduration;
37527
- this._playlistType = data.details.type || null;
37528
- var startTimeChanged = false;
37529
- var durationChanged = false;
37530
- var fragments = data.details.fragments;
37531
- var previousPlayableRegionStartTime = this._playableRegionStartTime;
37532
- var previousPlayableRegionDuration = this._playableRegionDuration;
37533
- if (fragments.length === 0) return;
37534
- // #EXT-X-PROGRAM-DATE-TIME
37535
- if (fragments[0].rawProgramDateTime) {
37536
- this._programDateTime = fragments[0].rawProgramDateTime;
37537
- }
37538
- if (this._playableRegionStartTime !== fragments[0].start) {
37539
- startTimeChanged = true;
37540
- this._playableRegionStartTime = fragments[0].start;
37541
- }
37542
- if (startTimeChanged) {
37543
- if (!this._localStartTimeCorrelation) {
37544
- // set the correlation to map to middle of the extrapolation window
37276
+ } else {
37277
+ // check if the correlation still works
37278
+ const corr = this._localStartTimeCorrelation;
37279
+ const timePassed = this._now - corr.local;
37280
+ // this should point to a time within the extrapolation window
37281
+ const startTime = (corr.remote + timePassed) / 1000;
37282
+ if (startTime < fragments[0].start) {
37283
+ // our start time is now earlier than the first chunk
37284
+ // (maybe the chunk was removed early)
37285
+ // reset correlation so that it sits at the beginning of the first available chunk
37545
37286
  this._localStartTimeCorrelation = {
37546
37287
  local: this._now,
37547
- remote: (fragments[0].start + this._extrapolatedWindowDuration / 2) * 1000
37288
+ remote: fragments[0].start * 1000
37289
+ };
37290
+ } else if (startTime > previousPlayableRegionStartTime + this._extrapolatedWindowDuration) {
37291
+ // start time was past the end of the old extrapolation window (so would have been capped)
37292
+ // see if now that time would be inside the window, and if it would be set the correlation
37293
+ // so that it resumes from the time it was at at the end of the old window
37294
+ // update the correlation so that the time starts counting again from the value it's on now
37295
+ this._localStartTimeCorrelation = {
37296
+ local: this._now,
37297
+ remote: Math.max(fragments[0].start, previousPlayableRegionStartTime + this._extrapolatedWindowDuration) * 1000
37548
37298
  };
37549
- } else {
37550
- // check if the correlation still works
37551
- var corr = this._localStartTimeCorrelation;
37552
- var timePassed = this._now - corr.local;
37553
- // this should point to a time within the extrapolation window
37554
- var startTime = (corr.remote + timePassed) / 1000;
37555
- if (startTime < fragments[0].start) {
37556
- // our start time is now earlier than the first chunk
37557
- // (maybe the chunk was removed early)
37558
- // reset correlation so that it sits at the beginning of the first available chunk
37559
- this._localStartTimeCorrelation = {
37560
- local: this._now,
37561
- remote: fragments[0].start * 1000
37562
- };
37563
- } else if (startTime > previousPlayableRegionStartTime + this._extrapolatedWindowDuration) {
37564
- // start time was past the end of the old extrapolation window (so would have been capped)
37565
- // see if now that time would be inside the window, and if it would be set the correlation
37566
- // so that it resumes from the time it was at at the end of the old window
37567
- // update the correlation so that the time starts counting again from the value it's on now
37568
- this._localStartTimeCorrelation = {
37569
- local: this._now,
37570
- remote: Math.max(fragments[0].start, previousPlayableRegionStartTime + this._extrapolatedWindowDuration) * 1000
37571
- };
37572
- }
37573
- }
37574
- }
37575
- var newDuration = data.details.totalduration;
37576
- // if it's a live stream then shorten the duration to remove access
37577
- // to the area after hlsjs's live sync point
37578
- // seeks to areas after this point sometimes have issues
37579
- if (this._playbackType === Playback.LIVE) {
37580
- var fragmentTargetDuration = data.details.targetduration;
37581
- var hlsjsConfig = this.options.playback.hlsjsConfig || {};
37582
- var liveSyncDurationCount = hlsjsConfig.liveSyncDurationCount || Hls.DefaultConfig.liveSyncDurationCount;
37583
- var hiddenAreaDuration = fragmentTargetDuration * liveSyncDurationCount;
37584
- if (hiddenAreaDuration <= newDuration) {
37585
- newDuration -= hiddenAreaDuration;
37586
- this._durationExcludesAfterLiveSyncPoint = true;
37587
- } else {
37588
- this._durationExcludesAfterLiveSyncPoint = false;
37589
37299
  }
37590
37300
  }
37591
- if (newDuration !== this._playableRegionDuration) {
37592
- durationChanged = true;
37593
- this._playableRegionDuration = newDuration;
37594
- }
37595
- // Note the end time is not the playableRegionDuration
37596
- // The end time will always increase even if content is removed from the beginning
37597
- var endTime = fragments[0].start + newDuration;
37598
- var previousEndTime = previousPlayableRegionStartTime + previousPlayableRegionDuration;
37599
- var endTimeChanged = endTime !== previousEndTime;
37600
- if (endTimeChanged) {
37601
- if (!this._localEndTimeCorrelation) {
37602
- // set the correlation to map to the end
37301
+ }
37302
+ let newDuration = data.details.totalduration;
37303
+ // if it's a live stream then shorten the duration to remove access
37304
+ // to the area after hlsjs's live sync point
37305
+ // seeks to areas after this point sometimes have issues
37306
+ if (this._playbackType === Playback.LIVE) {
37307
+ const fragmentTargetDuration = data.details.targetduration;
37308
+ const hlsjsConfig = this.options.playback.hlsjsConfig || {};
37309
+ const liveSyncDurationCount = hlsjsConfig.liveSyncDurationCount || Hls.DefaultConfig.liveSyncDurationCount;
37310
+ const hiddenAreaDuration = fragmentTargetDuration * liveSyncDurationCount;
37311
+ if (hiddenAreaDuration <= newDuration) {
37312
+ newDuration -= hiddenAreaDuration;
37313
+ this._durationExcludesAfterLiveSyncPoint = true;
37314
+ } else {
37315
+ this._durationExcludesAfterLiveSyncPoint = false;
37316
+ }
37317
+ }
37318
+ if (newDuration !== this._playableRegionDuration) {
37319
+ durationChanged = true;
37320
+ this._playableRegionDuration = newDuration;
37321
+ }
37322
+ // Note the end time is not the playableRegionDuration
37323
+ // The end time will always increase even if content is removed from the beginning
37324
+ const endTime = fragments[0].start + newDuration;
37325
+ const previousEndTime = previousPlayableRegionStartTime + previousPlayableRegionDuration;
37326
+ const endTimeChanged = endTime !== previousEndTime;
37327
+ if (endTimeChanged) {
37328
+ if (!this._localEndTimeCorrelation) {
37329
+ // set the correlation to map to the end
37330
+ this._localEndTimeCorrelation = {
37331
+ local: this._now,
37332
+ remote: endTime * 1000
37333
+ };
37334
+ } else {
37335
+ // check if the correlation still works
37336
+ const corr = this._localEndTimeCorrelation;
37337
+ const timePassed = this._now - corr.local;
37338
+ // this should point to a time within the extrapolation window from the end
37339
+ const extrapolatedEndTime = (corr.remote + timePassed) / 1000;
37340
+ if (extrapolatedEndTime > endTime) {
37603
37341
  this._localEndTimeCorrelation = {
37604
37342
  local: this._now,
37605
37343
  remote: endTime * 1000
37606
37344
  };
37607
- } else {
37608
- // check if the correlation still works
37609
- var _corr = this._localEndTimeCorrelation;
37610
- var _timePassed = this._now - _corr.local;
37611
- // this should point to a time within the extrapolation window from the end
37612
- var extrapolatedEndTime = (_corr.remote + _timePassed) / 1000;
37613
- if (extrapolatedEndTime > endTime) {
37614
- this._localEndTimeCorrelation = {
37615
- local: this._now,
37616
- remote: endTime * 1000
37617
- };
37618
- } else if (extrapolatedEndTime < endTime - this._extrapolatedWindowDuration) {
37619
- // our extrapolated end time is now earlier than the extrapolation window from the actual end time
37620
- // (maybe a chunk became available early)
37621
- // reset correlation so that it sits at the beginning of the extrapolation window from the end time
37622
- this._localEndTimeCorrelation = {
37623
- local: this._now,
37624
- remote: (endTime - this._extrapolatedWindowDuration) * 1000
37625
- };
37626
- } else if (extrapolatedEndTime > previousEndTime) {
37627
- // end time was past the old end time (so would have been capped)
37628
- // set the correlation so that it resumes from the time it was at at the end of the old window
37629
- this._localEndTimeCorrelation = {
37630
- local: this._now,
37631
- remote: previousEndTime * 1000
37632
- };
37633
- }
37345
+ } else if (extrapolatedEndTime < endTime - this._extrapolatedWindowDuration) {
37346
+ // our extrapolated end time is now earlier than the extrapolation window from the actual end time
37347
+ // (maybe a chunk became available early)
37348
+ // reset correlation so that it sits at the beginning of the extrapolation window from the end time
37349
+ this._localEndTimeCorrelation = {
37350
+ local: this._now,
37351
+ remote: (endTime - this._extrapolatedWindowDuration) * 1000
37352
+ };
37353
+ } else if (extrapolatedEndTime > previousEndTime) {
37354
+ // end time was past the old end time (so would have been capped)
37355
+ // set the correlation so that it resumes from the time it was at at the end of the old window
37356
+ this._localEndTimeCorrelation = {
37357
+ local: this._now,
37358
+ remote: previousEndTime * 1000
37359
+ };
37634
37360
  }
37635
37361
  }
37636
-
37637
- // now that the values have been updated call any methods that use on them so they get the updated values
37638
- // immediately
37639
- durationChanged && this._onDurationChange();
37640
- startTimeChanged && this._onProgress();
37641
- }
37642
- }, {
37643
- key: "_onFragmentChanged",
37644
- value: function _onFragmentChanged(evt, data) {
37645
- this._currentFragment = data.frag;
37646
- this.trigger(Events$1.Custom.PLAYBACK_FRAGMENT_CHANGED, data);
37647
- }
37648
- }, {
37649
- key: "_onFragmentLoaded",
37650
- value: function _onFragmentLoaded(evt, data) {
37651
- this.trigger(Events$1.PLAYBACK_FRAGMENT_LOADED, data);
37652
- }
37653
- }, {
37654
- key: "_onFragmentBuffered",
37655
- value: function _onFragmentBuffered(evt, data) {
37656
- this.trigger(Events$1.PLAYBACK_FRAGMENT_BUFFERED, data);
37657
- }
37658
- }, {
37659
- key: "_onSubtitleLoaded",
37660
- value: function _onSubtitleLoaded() {
37661
- // This event may be triggered multiple times
37662
- // Setup CC only once (disable CC by default)
37663
- if (!this._ccIsSetup) {
37664
- this.trigger(Events$1.PLAYBACK_SUBTITLE_AVAILABLE);
37665
- var trackId = this._playbackType === Playback.LIVE ? -1 : this.closedCaptionsTrackId;
37666
- this.closedCaptionsTrackId = trackId;
37667
- this._ccIsSetup = true;
37668
- }
37669
- }
37670
- }, {
37671
- key: "_onLevelSwitch",
37672
- value: function _onLevelSwitch(evt, data) {
37673
- if (!this.levels.length) this._fillLevels();
37674
- this.trigger(Events$1.PLAYBACK_LEVEL_SWITCH_END);
37675
- this.trigger(Events$1.PLAYBACK_LEVEL_SWITCH, data);
37676
- var currentLevel = this._hls.levels[data.level];
37677
- if (currentLevel) {
37678
- // TODO should highDefinition be private and maybe have a read only accessor if it's used somewhere
37679
- this.highDefinition = currentLevel.height >= 720 || currentLevel.bitrate / 1000 >= 2000;
37680
- this.trigger(Events$1.PLAYBACK_HIGHDEFINITIONUPDATE, this.highDefinition);
37681
- this.trigger(Events$1.PLAYBACK_BITRATE, {
37682
- height: currentLevel.height,
37683
- width: currentLevel.width,
37684
- bandwidth: currentLevel.bitrate,
37685
- bitrate: currentLevel.bitrate,
37686
- level: data.level
37687
- });
37688
- }
37689
- }
37690
- }, {
37691
- key: "dvrEnabled",
37692
- get: function get() {
37693
- // enabled when:
37694
- // - the duration does not include content after hlsjs's live sync point
37695
- // - the playable region duration is longer than the configured duration to enable dvr after
37696
- // - the playback type is LIVE.
37697
- return this._durationExcludesAfterLiveSyncPoint && this._duration >= this._minDvrSize && this.getPlaybackType() === Playback.LIVE;
37698
37362
  }
37699
- }, {
37700
- key: "getPlaybackType",
37701
- value: function getPlaybackType() {
37702
- return this._playbackType;
37703
- }
37704
- }, {
37705
- key: "isSeekEnabled",
37706
- value: function isSeekEnabled() {
37707
- return this._playbackType === Playback.VOD || this.dvrEnabled;
37708
- }
37709
- }], [{
37710
- key: "HLSJS",
37711
- get: function get() {
37712
- return Hls;
37363
+
37364
+ // now that the values have been updated call any methods that use on them so they get the updated values
37365
+ // immediately
37366
+ durationChanged && this._onDurationChange();
37367
+ startTimeChanged && this._onProgress();
37368
+ }
37369
+ _onFragmentChanged(evt, data) {
37370
+ this._currentFragment = data.frag;
37371
+ this.trigger(Events$1.Custom.PLAYBACK_FRAGMENT_CHANGED, data);
37372
+ }
37373
+ _onFragmentLoaded(evt, data) {
37374
+ this.trigger(Events$1.PLAYBACK_FRAGMENT_LOADED, data);
37375
+ }
37376
+ _onFragmentBuffered(evt, data) {
37377
+ this.trigger(Events$1.PLAYBACK_FRAGMENT_BUFFERED, data);
37378
+ }
37379
+ _onSubtitleLoaded() {
37380
+ // This event may be triggered multiple times
37381
+ // Setup CC only once (disable CC by default)
37382
+ if (!this._ccIsSetup) {
37383
+ this.trigger(Events$1.PLAYBACK_SUBTITLE_AVAILABLE);
37384
+ const trackId = this._playbackType === Playback.LIVE ? -1 : this.closedCaptionsTrackId;
37385
+ this.closedCaptionsTrackId = trackId;
37386
+ this._ccIsSetup = true;
37387
+ }
37388
+ }
37389
+ _onLevelSwitch(evt, data) {
37390
+ if (!this.levels.length) this._fillLevels();
37391
+ this.trigger(Events$1.PLAYBACK_LEVEL_SWITCH_END);
37392
+ this.trigger(Events$1.PLAYBACK_LEVEL_SWITCH, data);
37393
+ const currentLevel = this._hls.levels[data.level];
37394
+ if (currentLevel) {
37395
+ // TODO should highDefinition be private and maybe have a read only accessor if it's used somewhere
37396
+ this.highDefinition = currentLevel.height >= 720 || currentLevel.bitrate / 1000 >= 2000;
37397
+ this.trigger(Events$1.PLAYBACK_HIGHDEFINITIONUPDATE, this.highDefinition);
37398
+ this.trigger(Events$1.PLAYBACK_BITRATE, {
37399
+ height: currentLevel.height,
37400
+ width: currentLevel.width,
37401
+ bandwidth: currentLevel.bitrate,
37402
+ bitrate: currentLevel.bitrate,
37403
+ level: data.level
37404
+ });
37713
37405
  }
37714
- }]);
37715
- }(HTML5Video);
37406
+ }
37407
+ get dvrEnabled() {
37408
+ // enabled when:
37409
+ // - the duration does not include content after hlsjs's live sync point
37410
+ // - the playable region duration is longer than the configured duration to enable dvr after
37411
+ // - the playback type is LIVE.
37412
+ return this._durationExcludesAfterLiveSyncPoint && this._duration >= this._minDvrSize && this.getPlaybackType() === Playback.LIVE;
37413
+ }
37414
+ getPlaybackType() {
37415
+ return this._playbackType;
37416
+ }
37417
+ isSeekEnabled() {
37418
+ return this._playbackType === Playback.VOD || this.dvrEnabled;
37419
+ }
37420
+ }
37716
37421
  HlsjsPlayback.canPlay = function (resource, mimeType) {
37717
- var resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || [];
37718
- var isHls = resourceParts.length > 1 && resourceParts[1].toLowerCase() === 'm3u8' || listContainsIgnoreCase(mimeType, ['application/vnd.apple.mpegurl', 'application/x-mpegURL']);
37422
+ const resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || [];
37423
+ const isHls = resourceParts.length > 1 && resourceParts[1].toLowerCase() === 'm3u8' || listContainsIgnoreCase(mimeType, ['application/vnd.apple.mpegurl', 'application/x-mpegURL']);
37719
37424
  return !!(Hls.isSupported() && isHls);
37720
37425
  };
37721
37426