rx-player 3.28.0-dev.2022063000 → 3.28.1-dev.2022083000
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.
- package/.github/workflows/checks.yml +20 -18
- package/CHANGELOG.md +14 -2
- package/VERSION +1 -1
- package/dist/_esm5.processed/compat/eme/load_session.d.ts +5 -6
- package/dist/_esm5.processed/compat/eme/load_session.js +5 -6
- package/dist/_esm5.processed/compat/event_listeners.js +5 -0
- package/dist/_esm5.processed/core/api/media_element_track_choice_manager.js +1 -1
- package/dist/_esm5.processed/core/api/public_api.js +2 -2
- package/dist/_esm5.processed/core/decrypt/create_session.js +33 -4
- package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.d.ts +14 -0
- package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.js +25 -0
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.d.ts +1 -1
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.js +1 -1
- package/dist/_esm5.processed/core/init/content_time_boundaries_observer.js +110 -38
- package/dist/_esm5.processed/core/stream/representation/check_for_discontinuity.js +21 -9
- package/dist/_esm5.processed/core/stream/representation/get_buffer_status.js +21 -29
- package/dist/_esm5.processed/errors/encrypted_media_error.d.ts +1 -2
- package/dist/_esm5.processed/errors/encrypted_media_error.js +0 -1
- package/dist/_esm5.processed/errors/error_codes.d.ts +6 -1
- package/dist/_esm5.processed/errors/media_error.d.ts +1 -2
- package/dist/_esm5.processed/errors/media_error.js +0 -1
- package/dist/_esm5.processed/errors/network_error.d.ts +1 -2
- package/dist/_esm5.processed/errors/network_error.js +0 -1
- package/dist/_esm5.processed/errors/other_error.d.ts +1 -2
- package/dist/_esm5.processed/errors/other_error.js +0 -1
- package/dist/_esm5.processed/manifest/manifest.d.ts +1 -1
- package/dist/_esm5.processed/manifest/manifest.js +1 -1
- package/dist/_esm5.processed/manifest/representation_index/static.d.ts +21 -6
- package/dist/_esm5.processed/manifest/representation_index/static.js +26 -8
- package/dist/_esm5.processed/manifest/representation_index/types.d.ts +55 -44
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.d.ts +21 -8
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.js +25 -10
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.d.ts +26 -12
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.js +26 -13
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.d.ts +23 -7
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.js +65 -22
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.d.ts +20 -3
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.js +57 -7
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/{is_period_fulfilled.d.ts → utils.d.ts} +3 -6
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/{is_period_fulfilled.js → utils.js} +4 -8
- package/dist/_esm5.processed/parsers/manifest/dash/common/parse_periods.js +1 -1
- package/dist/_esm5.processed/parsers/manifest/local/parse_local_manifest.js +5 -8
- package/dist/_esm5.processed/parsers/manifest/local/representation_index.d.ts +21 -8
- package/dist/_esm5.processed/parsers/manifest/local/representation_index.js +49 -14
- package/dist/_esm5.processed/parsers/manifest/local/types.d.ts +16 -0
- package/dist/_esm5.processed/parsers/manifest/metaplaylist/representation_index.d.ts +20 -6
- package/dist/_esm5.processed/parsers/manifest/metaplaylist/representation_index.js +28 -10
- package/dist/_esm5.processed/parsers/manifest/smooth/create_parser.js +4 -4
- package/dist/_esm5.processed/parsers/manifest/smooth/representation_index.d.ts +21 -12
- package/dist/_esm5.processed/parsers/manifest/smooth/representation_index.js +39 -14
- package/dist/_esm5.processed/parsers/manifest/utils/get_first_time_from_adaptation.js +1 -1
- package/dist/_esm5.processed/parsers/manifest/utils/get_last_time_from_adaptation.js +1 -1
- package/dist/_esm5.processed/transports/metaplaylist/pipelines.js +0 -2
- package/dist/_esm5.processed/transports/smooth/segment_loader.js +1 -1
- package/dist/_esm5.processed/transports/types.d.ts +1 -1
- package/dist/_esm5.processed/utils/deep_merge.d.ts +1 -1
- package/dist/_esm5.processed/utils/deep_merge.js +6 -5
- package/dist/_esm5.processed/utils/task_canceller.d.ts +0 -3
- package/dist/_esm5.processed/utils/task_canceller.js +0 -3
- package/dist/mpd-parser.wasm +0 -0
- package/dist/rx-player.js +1390 -1059
- package/dist/rx-player.min.js +1 -1
- package/jest.config.js +5 -0
- package/package.json +31 -30
- package/sonar-project.properties +1 -1
- package/src/compat/eme/load_session.ts +5 -6
- package/src/compat/event_listeners.ts +5 -0
- package/src/core/api/media_element_track_choice_manager.ts +1 -1
- package/src/core/api/public_api.ts +2 -2
- package/src/core/decrypt/create_session.ts +28 -2
- package/src/core/decrypt/utils/loaded_sessions_store.ts +29 -0
- package/src/core/fetchers/segment/segment_fetcher.ts +1 -1
- package/src/core/init/content_time_boundaries_observer.ts +116 -42
- package/src/core/stream/representation/check_for_discontinuity.ts +28 -10
- package/src/core/stream/representation/get_buffer_status.ts +27 -34
- package/src/errors/encrypted_media_error.ts +1 -2
- package/src/errors/error_codes.ts +2 -2
- package/src/errors/media_error.ts +1 -2
- package/src/errors/network_error.ts +1 -2
- package/src/errors/other_error.ts +1 -2
- package/src/manifest/__tests__/adaptation.test.ts +4 -3
- package/src/manifest/__tests__/representation.test.ts +4 -3
- package/src/manifest/manifest.ts +1 -1
- package/src/manifest/representation_index/__tests__/static.test.ts +5 -4
- package/src/manifest/representation_index/static.ts +28 -9
- package/src/manifest/representation_index/types.ts +62 -46
- package/src/parsers/manifest/dash/common/indexes/base.ts +27 -11
- package/src/parsers/manifest/dash/common/indexes/list.ts +32 -15
- package/src/parsers/manifest/dash/common/indexes/template.ts +73 -27
- package/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts +60 -8
- package/src/parsers/manifest/dash/common/indexes/{is_period_fulfilled.ts → utils.ts} +4 -13
- package/src/parsers/manifest/dash/common/parse_periods.ts +1 -1
- package/src/parsers/manifest/local/parse_local_manifest.ts +8 -20
- package/src/parsers/manifest/local/representation_index.ts +51 -16
- package/src/parsers/manifest/local/types.ts +13 -0
- package/src/parsers/manifest/metaplaylist/representation_index.ts +31 -11
- package/src/parsers/manifest/smooth/create_parser.ts +4 -4
- package/src/parsers/manifest/smooth/representation_index.ts +40 -15
- package/src/parsers/manifest/utils/__tests__/get_first_time_from_adaptations.test.ts +4 -3
- package/src/parsers/manifest/utils/__tests__/get_last_time_from_adaptation.test.ts +4 -3
- package/src/parsers/manifest/utils/get_first_time_from_adaptation.ts +1 -1
- package/src/parsers/manifest/utils/get_last_time_from_adaptation.ts +1 -1
- package/src/transports/metaplaylist/pipelines.ts +0 -2
- package/src/transports/smooth/segment_loader.ts +1 -1
- package/src/transports/types.ts +1 -1
- package/src/utils/__tests__/initialization_segment_cache.test.ts +7 -0
- package/src/utils/deep_merge.ts +7 -4
- package/src/utils/task_canceller.ts +0 -3
|
@@ -60,7 +60,7 @@ var ListRepresentationIndex = /** @class */ (function () {
|
|
|
60
60
|
};
|
|
61
61
|
/**
|
|
62
62
|
* @param {Number} fromTime
|
|
63
|
-
* @param {Number}
|
|
63
|
+
* @param {Number} dur
|
|
64
64
|
* @returns {Array.<Object>}
|
|
65
65
|
*/
|
|
66
66
|
ListRepresentationIndex.prototype.getSegments = function (fromTime, dur) {
|
|
@@ -104,23 +104,45 @@ var ListRepresentationIndex = /** @class */ (function () {
|
|
|
104
104
|
* Returns first position in this index, in seconds.
|
|
105
105
|
* @returns {Number}
|
|
106
106
|
*/
|
|
107
|
-
ListRepresentationIndex.prototype.
|
|
107
|
+
ListRepresentationIndex.prototype.getFirstAvailablePosition = function () {
|
|
108
108
|
return this._periodStart;
|
|
109
109
|
};
|
|
110
110
|
/**
|
|
111
111
|
* Returns last position in this index, in seconds.
|
|
112
112
|
* @returns {Number}
|
|
113
113
|
*/
|
|
114
|
-
ListRepresentationIndex.prototype.
|
|
114
|
+
ListRepresentationIndex.prototype.getLastAvailablePosition = function () {
|
|
115
115
|
var _a;
|
|
116
116
|
var index = this._index;
|
|
117
117
|
var duration = index.duration, list = index.list;
|
|
118
118
|
return Math.min(((list.length * duration) / index.timescale) + this._periodStart, (_a = this._periodEnd) !== null && _a !== void 0 ? _a : Infinity);
|
|
119
119
|
};
|
|
120
|
+
/**
|
|
121
|
+
* Returns the absolute end in seconds this RepresentationIndex can reach once
|
|
122
|
+
* all segments are available.
|
|
123
|
+
* @returns {number|null|undefined}
|
|
124
|
+
*/
|
|
125
|
+
ListRepresentationIndex.prototype.getEnd = function () {
|
|
126
|
+
return this.getLastAvailablePosition();
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Returns:
|
|
130
|
+
* - `true` if in the given time interval, at least one new segment is
|
|
131
|
+
* expected to be available in the future.
|
|
132
|
+
* - `false` either if all segments in that time interval are already
|
|
133
|
+
* available for download or if none will ever be available for it.
|
|
134
|
+
* - `undefined` when it is not possible to tell.
|
|
135
|
+
*
|
|
136
|
+
* Always `false` in a `ListRepresentationIndex` because all segments should
|
|
137
|
+
* be directly available.
|
|
138
|
+
* @returns {boolean}
|
|
139
|
+
*/
|
|
140
|
+
ListRepresentationIndex.prototype.awaitSegmentBetween = function () {
|
|
141
|
+
return false;
|
|
142
|
+
};
|
|
120
143
|
/**
|
|
121
144
|
* Returns true if a Segment returned by this index is still considered
|
|
122
145
|
* available.
|
|
123
|
-
* @param {Object} segment
|
|
124
146
|
* @returns {Boolean}
|
|
125
147
|
*/
|
|
126
148
|
ListRepresentationIndex.prototype.isSegmentStillAvailable = function () {
|
|
@@ -133,12 +155,6 @@ var ListRepresentationIndex = /** @class */ (function () {
|
|
|
133
155
|
ListRepresentationIndex.prototype.checkDiscontinuity = function () {
|
|
134
156
|
return null;
|
|
135
157
|
};
|
|
136
|
-
/**
|
|
137
|
-
* @returns {boolean}
|
|
138
|
-
*/
|
|
139
|
-
ListRepresentationIndex.prototype.areSegmentsChronologicallyGenerated = function () {
|
|
140
|
-
return true;
|
|
141
|
-
};
|
|
142
158
|
/**
|
|
143
159
|
* SegmentList should not be updated.
|
|
144
160
|
* @returns {Boolean}
|
|
@@ -164,9 +180,6 @@ var ListRepresentationIndex = /** @class */ (function () {
|
|
|
164
180
|
ListRepresentationIndex.prototype._replace = function (newIndex) {
|
|
165
181
|
this._index = newIndex._index;
|
|
166
182
|
};
|
|
167
|
-
/**
|
|
168
|
-
* @param {Object} newIndex
|
|
169
|
-
*/
|
|
170
183
|
ListRepresentationIndex.prototype._update = function () {
|
|
171
184
|
log.error("List RepresentationIndex: Cannot update a SegmentList");
|
|
172
185
|
};
|
|
@@ -46,6 +46,7 @@ export interface ITemplateIndex {
|
|
|
46
46
|
/**
|
|
47
47
|
* URL base to access any segment.
|
|
48
48
|
* Can contain token to replace to convert it to real URLs.
|
|
49
|
+
* `null` if no URL exists.
|
|
49
50
|
*/
|
|
50
51
|
mediaURLs: string[] | null;
|
|
51
52
|
/**
|
|
@@ -134,7 +135,7 @@ export default class TemplateRepresentationIndex implements IRepresentationIndex
|
|
|
134
135
|
/** Absolute start of the Period, in seconds. */
|
|
135
136
|
private _periodStart;
|
|
136
137
|
/** Difference between the end time of the Period and its start time, in timescale. */
|
|
137
|
-
private
|
|
138
|
+
private _scaledRelativePeriodEnd;
|
|
138
139
|
/** Minimum availabilityTimeOffset concerning the segments of this Representation. */
|
|
139
140
|
private _availabilityTimeOffset;
|
|
140
141
|
/** Whether the corresponding Manifest can be updated and changed. */
|
|
@@ -160,12 +161,31 @@ export default class TemplateRepresentationIndex implements IRepresentationIndex
|
|
|
160
161
|
* Returns first possible position in the index, in seconds.
|
|
161
162
|
* @returns {number|null|undefined}
|
|
162
163
|
*/
|
|
163
|
-
|
|
164
|
+
getFirstAvailablePosition(): number | null | undefined;
|
|
164
165
|
/**
|
|
165
166
|
* Returns last possible position in the index, in seconds.
|
|
166
167
|
* @returns {number|null}
|
|
167
168
|
*/
|
|
168
|
-
|
|
169
|
+
getLastAvailablePosition(): number | null | undefined;
|
|
170
|
+
/**
|
|
171
|
+
* Returns the absolute end in seconds this RepresentationIndex can reach once
|
|
172
|
+
* all segments are available.
|
|
173
|
+
* @returns {number|null|undefined}
|
|
174
|
+
*/
|
|
175
|
+
getEnd(): number | null | undefined;
|
|
176
|
+
/**
|
|
177
|
+
* Returns:
|
|
178
|
+
* - `true` if in the given time interval, at least one new segment is
|
|
179
|
+
* expected to be available in the future.
|
|
180
|
+
* - `false` either if all segments in that time interval are already
|
|
181
|
+
* available for download or if none will ever be available for it.
|
|
182
|
+
* - `undefined` when it is not possible to tell.
|
|
183
|
+
*
|
|
184
|
+
* Always `false` in a `BaseRepresentationIndex` because all segments should
|
|
185
|
+
* be directly available.
|
|
186
|
+
* @returns {boolean}
|
|
187
|
+
*/
|
|
188
|
+
awaitSegmentBetween(start: number, end: number): boolean | undefined;
|
|
169
189
|
/**
|
|
170
190
|
* Returns true if, based on the arguments, the index should be refreshed.
|
|
171
191
|
* We never have to refresh a SegmentTemplate-based manifest.
|
|
@@ -177,10 +197,6 @@ export default class TemplateRepresentationIndex implements IRepresentationIndex
|
|
|
177
197
|
* @returns {null}
|
|
178
198
|
*/
|
|
179
199
|
checkDiscontinuity(): null;
|
|
180
|
-
/**
|
|
181
|
-
* @returns {Boolean}
|
|
182
|
-
*/
|
|
183
|
-
areSegmentsChronologicallyGenerated(): true;
|
|
184
200
|
/**
|
|
185
201
|
* Returns `true` if the given segment should still be available as of now
|
|
186
202
|
* (not removed since and still request-able).
|
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import config from "../../../../../config";
|
|
17
|
+
import assert from "../../../../../utils/assert";
|
|
17
18
|
import getInitSegment from "./get_init_segment";
|
|
18
|
-
import isPeriodFulfilled from "./is_period_fulfilled";
|
|
19
19
|
import { createDashUrlDetokenizer, createIndexURLs, } from "./tokens";
|
|
20
|
+
import { getSegmentTimeRoundingError } from "./utils";
|
|
20
21
|
/**
|
|
21
22
|
* IRepresentationIndex implementation for DASH' SegmentTemplate without a
|
|
22
23
|
* SegmentTimeline.
|
|
@@ -55,7 +56,7 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
55
56
|
mediaURLs: createIndexURLs(urlSources, index.media, representationId, representationBitrate), presentationTimeOffset: presentationTimeOffset, startNumber: index.startNumber };
|
|
56
57
|
this._isDynamic = isDynamic;
|
|
57
58
|
this._periodStart = periodStart;
|
|
58
|
-
this.
|
|
59
|
+
this._scaledRelativePeriodEnd = periodEnd === undefined ?
|
|
59
60
|
undefined :
|
|
60
61
|
(periodEnd - periodStart) * timescale;
|
|
61
62
|
this._isEMSGWhitelisted = isEMSGWhitelisted;
|
|
@@ -76,7 +77,7 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
76
77
|
var index = this._index;
|
|
77
78
|
var duration = index.duration, startNumber = index.startNumber, timescale = index.timescale, mediaURLs = index.mediaURLs;
|
|
78
79
|
var scaledStart = this._periodStart * timescale;
|
|
79
|
-
var scaledEnd = this.
|
|
80
|
+
var scaledEnd = this._scaledRelativePeriodEnd;
|
|
80
81
|
// Convert the asked position to the right timescales, and consider them
|
|
81
82
|
// relatively to the Period's start.
|
|
82
83
|
var upFromPeriodStart = fromTime * timescale - scaledStart;
|
|
@@ -132,7 +133,7 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
132
133
|
* Returns first possible position in the index, in seconds.
|
|
133
134
|
* @returns {number|null|undefined}
|
|
134
135
|
*/
|
|
135
|
-
TemplateRepresentationIndex.prototype.
|
|
136
|
+
TemplateRepresentationIndex.prototype.getFirstAvailablePosition = function () {
|
|
136
137
|
var firstSegmentStart = this._getFirstSegmentStart();
|
|
137
138
|
if (firstSegmentStart == null) {
|
|
138
139
|
return firstSegmentStart; // return undefined or null
|
|
@@ -143,18 +144,64 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
143
144
|
* Returns last possible position in the index, in seconds.
|
|
144
145
|
* @returns {number|null}
|
|
145
146
|
*/
|
|
146
|
-
TemplateRepresentationIndex.prototype.
|
|
147
|
+
TemplateRepresentationIndex.prototype.getLastAvailablePosition = function () {
|
|
147
148
|
var _a;
|
|
148
149
|
var lastSegmentStart = this._getLastSegmentStart();
|
|
149
150
|
if (lastSegmentStart == null) {
|
|
150
|
-
// In that case (null or undefined),
|
|
151
|
+
// In that case (null or undefined), getLastAvailablePosition should reflect
|
|
151
152
|
// the result of getLastSegmentStart, as the meaning is the same for
|
|
152
153
|
// the two functions. So, we return the result of the latter.
|
|
153
154
|
return lastSegmentStart;
|
|
154
155
|
}
|
|
155
|
-
var lastSegmentEnd = Math.min(lastSegmentStart + this._index.duration, (_a = this.
|
|
156
|
+
var lastSegmentEnd = Math.min(lastSegmentStart + this._index.duration, (_a = this._scaledRelativePeriodEnd) !== null && _a !== void 0 ? _a : Infinity);
|
|
156
157
|
return (lastSegmentEnd / this._index.timescale) + this._periodStart;
|
|
157
158
|
};
|
|
159
|
+
/**
|
|
160
|
+
* Returns the absolute end in seconds this RepresentationIndex can reach once
|
|
161
|
+
* all segments are available.
|
|
162
|
+
* @returns {number|null|undefined}
|
|
163
|
+
*/
|
|
164
|
+
TemplateRepresentationIndex.prototype.getEnd = function () {
|
|
165
|
+
if (!this._isDynamic) {
|
|
166
|
+
return this.getLastAvailablePosition();
|
|
167
|
+
}
|
|
168
|
+
if (this._scaledRelativePeriodEnd === undefined) {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
var timescale = this._index.timescale;
|
|
172
|
+
var absoluteScaledPeriodEnd = (this._scaledRelativePeriodEnd +
|
|
173
|
+
this._periodStart * timescale);
|
|
174
|
+
return absoluteScaledPeriodEnd / this._index.timescale;
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Returns:
|
|
178
|
+
* - `true` if in the given time interval, at least one new segment is
|
|
179
|
+
* expected to be available in the future.
|
|
180
|
+
* - `false` either if all segments in that time interval are already
|
|
181
|
+
* available for download or if none will ever be available for it.
|
|
182
|
+
* - `undefined` when it is not possible to tell.
|
|
183
|
+
*
|
|
184
|
+
* Always `false` in a `BaseRepresentationIndex` because all segments should
|
|
185
|
+
* be directly available.
|
|
186
|
+
* @returns {boolean}
|
|
187
|
+
*/
|
|
188
|
+
TemplateRepresentationIndex.prototype.awaitSegmentBetween = function (start, end) {
|
|
189
|
+
assert(start <= end);
|
|
190
|
+
if (!this._isDynamic) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
var timescale = this._index.timescale;
|
|
194
|
+
var segmentTimeRounding = getSegmentTimeRoundingError(timescale);
|
|
195
|
+
var scaledPeriodStart = this._periodStart * timescale;
|
|
196
|
+
var scaledRelativeEnd = end * timescale - scaledPeriodStart;
|
|
197
|
+
if (this._scaledRelativePeriodEnd === undefined) {
|
|
198
|
+
return (scaledRelativeEnd + segmentTimeRounding) >= 0;
|
|
199
|
+
}
|
|
200
|
+
var scaledRelativePeriodEnd = this._scaledRelativePeriodEnd;
|
|
201
|
+
var scaledRelativeStart = start * timescale - scaledPeriodStart;
|
|
202
|
+
return (scaledRelativeStart - segmentTimeRounding) < scaledRelativePeriodEnd &&
|
|
203
|
+
(scaledRelativeEnd + segmentTimeRounding) >= 0;
|
|
204
|
+
};
|
|
158
205
|
/**
|
|
159
206
|
* Returns true if, based on the arguments, the index should be refreshed.
|
|
160
207
|
* We never have to refresh a SegmentTemplate-based manifest.
|
|
@@ -170,12 +217,6 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
170
217
|
TemplateRepresentationIndex.prototype.checkDiscontinuity = function () {
|
|
171
218
|
return null;
|
|
172
219
|
};
|
|
173
|
-
/**
|
|
174
|
-
* @returns {Boolean}
|
|
175
|
-
*/
|
|
176
|
-
TemplateRepresentationIndex.prototype.areSegmentsChronologicallyGenerated = function () {
|
|
177
|
-
return true;
|
|
178
|
-
};
|
|
179
220
|
/**
|
|
180
221
|
* Returns `true` if the given segment should still be available as of now
|
|
181
222
|
* (not removed since and still request-able).
|
|
@@ -210,7 +251,7 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
210
251
|
if (!this._isDynamic) {
|
|
211
252
|
return true;
|
|
212
253
|
}
|
|
213
|
-
if (this.
|
|
254
|
+
if (this._scaledRelativePeriodEnd === undefined) {
|
|
214
255
|
return false;
|
|
215
256
|
}
|
|
216
257
|
var timescale = this._index.timescale;
|
|
@@ -221,7 +262,8 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
221
262
|
return false;
|
|
222
263
|
}
|
|
223
264
|
var lastSegmentEnd = lastSegmentStart + this._index.duration;
|
|
224
|
-
|
|
265
|
+
var segmentTimeRounding = getSegmentTimeRoundingError(timescale);
|
|
266
|
+
return (lastSegmentEnd + segmentTimeRounding) >= this._scaledRelativePeriodEnd;
|
|
225
267
|
};
|
|
226
268
|
/**
|
|
227
269
|
* @returns {Boolean}
|
|
@@ -237,7 +279,7 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
237
279
|
this._aggressiveMode = newIndex._aggressiveMode;
|
|
238
280
|
this._isDynamic = newIndex._isDynamic;
|
|
239
281
|
this._periodStart = newIndex._periodStart;
|
|
240
|
-
this.
|
|
282
|
+
this._scaledRelativePeriodEnd = newIndex._scaledRelativePeriodEnd;
|
|
241
283
|
this._manifestBoundsCalculator = newIndex._manifestBoundsCalculator;
|
|
242
284
|
};
|
|
243
285
|
/**
|
|
@@ -258,7 +300,8 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
258
300
|
return 0; // it is the start of the Period
|
|
259
301
|
}
|
|
260
302
|
// 1 - check that this index is already available
|
|
261
|
-
if (this.
|
|
303
|
+
if (this._scaledRelativePeriodEnd === 0 ||
|
|
304
|
+
this._scaledRelativePeriodEnd === undefined) {
|
|
262
305
|
// /!\ The scaled max position augments continuously and might not
|
|
263
306
|
// reflect exactly the real server-side value. As segments are
|
|
264
307
|
// generated discretely.
|
|
@@ -296,13 +339,13 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
296
339
|
}
|
|
297
340
|
var agressiveModeOffset = this._aggressiveMode ? (duration / timescale) :
|
|
298
341
|
0;
|
|
299
|
-
if (this.
|
|
300
|
-
this.
|
|
342
|
+
if (this._scaledRelativePeriodEnd != null &&
|
|
343
|
+
this._scaledRelativePeriodEnd <
|
|
301
344
|
(lastPos + agressiveModeOffset - this._periodStart) * this._index.timescale) {
|
|
302
|
-
if (this.
|
|
345
|
+
if (this._scaledRelativePeriodEnd < duration) {
|
|
303
346
|
return null;
|
|
304
347
|
}
|
|
305
|
-
return (Math.floor(this.
|
|
348
|
+
return (Math.floor(this._scaledRelativePeriodEnd / duration) - 1) * duration;
|
|
306
349
|
}
|
|
307
350
|
// /!\ The scaled last position augments continuously and might not
|
|
308
351
|
// reflect exactly the real server-side value. As segments are
|
|
@@ -321,7 +364,7 @@ var TemplateRepresentationIndex = /** @class */ (function () {
|
|
|
321
364
|
(numberOfSegmentsAvailable - 1) * duration;
|
|
322
365
|
}
|
|
323
366
|
else {
|
|
324
|
-
var maximumTime = (_a = this.
|
|
367
|
+
var maximumTime = (_a = this._scaledRelativePeriodEnd) !== null && _a !== void 0 ? _a : 0;
|
|
325
368
|
var numberIndexedToZero = Math.ceil(maximumTime / duration) - 1;
|
|
326
369
|
var regularLastSegmentStart = numberIndexedToZero * duration;
|
|
327
370
|
// In some SegmentTemplate, we could think that there is one more
|
|
@@ -219,14 +219,32 @@ export default class TimelineRepresentationIndex implements IRepresentationIndex
|
|
|
219
219
|
* Returns null if nothing is in the index
|
|
220
220
|
* @returns {Number|null}
|
|
221
221
|
*/
|
|
222
|
-
|
|
222
|
+
getFirstAvailablePosition(): number | null;
|
|
223
223
|
/**
|
|
224
224
|
* Returns the ending time, in seconds, of the last segment currently
|
|
225
225
|
* available.
|
|
226
226
|
* Returns null if nothing is in the index
|
|
227
227
|
* @returns {Number|null}
|
|
228
228
|
*/
|
|
229
|
-
|
|
229
|
+
getLastAvailablePosition(): number | null;
|
|
230
|
+
/**
|
|
231
|
+
* Returns the absolute end in seconds this RepresentationIndex can reach once
|
|
232
|
+
* all segments are available.
|
|
233
|
+
* @returns {number|null|undefined}
|
|
234
|
+
*/
|
|
235
|
+
getEnd(): number | undefined | null;
|
|
236
|
+
/**
|
|
237
|
+
* Returns:
|
|
238
|
+
* - `true` if in the given time interval, at least one new segment is
|
|
239
|
+
* expected to be available in the future.
|
|
240
|
+
* - `false` either if all segments in that time interval are already
|
|
241
|
+
* available for download or if none will ever be available for it.
|
|
242
|
+
* - `undefined` when it is not possible to tell.
|
|
243
|
+
* @param {number} start
|
|
244
|
+
* @param {number} end
|
|
245
|
+
* @returns {boolean|undefined}
|
|
246
|
+
*/
|
|
247
|
+
awaitSegmentBetween(start: number, end: number): boolean | undefined;
|
|
230
248
|
/**
|
|
231
249
|
* Returns true if a Segment returned by this index is still considered
|
|
232
250
|
* available.
|
|
@@ -250,7 +268,6 @@ export default class TimelineRepresentationIndex implements IRepresentationIndex
|
|
|
250
268
|
* @returns {Boolean}
|
|
251
269
|
*/
|
|
252
270
|
canBeOutOfSyncError(error: IPlayerError): boolean;
|
|
253
|
-
areSegmentsChronologicallyGenerated(): boolean;
|
|
254
271
|
/**
|
|
255
272
|
* Replace this RepresentationIndex with one from a new version of the
|
|
256
273
|
* Manifest.
|
|
@@ -16,14 +16,15 @@
|
|
|
16
16
|
import config from "../../../../../../config";
|
|
17
17
|
import { NetworkError } from "../../../../../../errors";
|
|
18
18
|
import log from "../../../../../../log";
|
|
19
|
+
import assert from "../../../../../../utils/assert";
|
|
19
20
|
import clearTimelineFromPosition from "../../../../utils/clear_timeline_from_position";
|
|
20
21
|
import { checkDiscontinuity, fromIndexTime, getIndexSegmentEnd, toIndexTime, } from "../../../../utils/index_helpers";
|
|
21
22
|
import isSegmentStillAvailable from "../../../../utils/is_segment_still_available";
|
|
22
23
|
import updateSegmentTimeline from "../../../../utils/update_segment_timeline";
|
|
23
24
|
import getInitSegment from "../get_init_segment";
|
|
24
25
|
import getSegmentsFromTimeline from "../get_segments_from_timeline";
|
|
25
|
-
import isPeriodFulfilled from "../is_period_fulfilled";
|
|
26
26
|
import { createIndexURLs } from "../tokens";
|
|
27
|
+
import { getSegmentTimeRoundingError } from "../utils";
|
|
27
28
|
import constructTimelineFromElements from "./construct_timeline_from_elements";
|
|
28
29
|
// eslint-disable-next-line max-len
|
|
29
30
|
import constructTimelineFromPreviousTimeline from "./construct_timeline_from_previous_timeline";
|
|
@@ -116,7 +117,7 @@ var TimelineRepresentationIndex = /** @class */ (function () {
|
|
|
116
117
|
* Returns null if nothing is in the index
|
|
117
118
|
* @returns {Number|null}
|
|
118
119
|
*/
|
|
119
|
-
TimelineRepresentationIndex.prototype.
|
|
120
|
+
TimelineRepresentationIndex.prototype.getFirstAvailablePosition = function () {
|
|
120
121
|
this._refreshTimeline();
|
|
121
122
|
if (this._index.timeline === null) {
|
|
122
123
|
this._index.timeline = this._getTimeline();
|
|
@@ -131,7 +132,7 @@ var TimelineRepresentationIndex = /** @class */ (function () {
|
|
|
131
132
|
* Returns null if nothing is in the index
|
|
132
133
|
* @returns {Number|null}
|
|
133
134
|
*/
|
|
134
|
-
TimelineRepresentationIndex.prototype.
|
|
135
|
+
TimelineRepresentationIndex.prototype.getLastAvailablePosition = function () {
|
|
135
136
|
this._refreshTimeline();
|
|
136
137
|
if (this._index.timeline === null) {
|
|
137
138
|
this._index.timeline = this._getTimeline();
|
|
@@ -140,6 +141,57 @@ var TimelineRepresentationIndex = /** @class */ (function () {
|
|
|
140
141
|
return lastTime === null ? null :
|
|
141
142
|
fromIndexTime(lastTime, this._index);
|
|
142
143
|
};
|
|
144
|
+
/**
|
|
145
|
+
* Returns the absolute end in seconds this RepresentationIndex can reach once
|
|
146
|
+
* all segments are available.
|
|
147
|
+
* @returns {number|null|undefined}
|
|
148
|
+
*/
|
|
149
|
+
TimelineRepresentationIndex.prototype.getEnd = function () {
|
|
150
|
+
if (!this._isDynamic || !this._isLastPeriod) { // @see isFinished
|
|
151
|
+
return this.getLastAvailablePosition();
|
|
152
|
+
}
|
|
153
|
+
return undefined;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Returns:
|
|
157
|
+
* - `true` if in the given time interval, at least one new segment is
|
|
158
|
+
* expected to be available in the future.
|
|
159
|
+
* - `false` either if all segments in that time interval are already
|
|
160
|
+
* available for download or if none will ever be available for it.
|
|
161
|
+
* - `undefined` when it is not possible to tell.
|
|
162
|
+
* @param {number} start
|
|
163
|
+
* @param {number} end
|
|
164
|
+
* @returns {boolean|undefined}
|
|
165
|
+
*/
|
|
166
|
+
TimelineRepresentationIndex.prototype.awaitSegmentBetween = function (start, end) {
|
|
167
|
+
var _a;
|
|
168
|
+
assert(start <= end);
|
|
169
|
+
if (!this._isDynamic || !this._isLastPeriod) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
this._refreshTimeline();
|
|
173
|
+
if (this._index.timeline === null) {
|
|
174
|
+
this._index.timeline = this._getTimeline();
|
|
175
|
+
}
|
|
176
|
+
var _b = this._index, timeline = _b.timeline, timescale = _b.timescale;
|
|
177
|
+
var segmentTimeRounding = getSegmentTimeRoundingError(timescale);
|
|
178
|
+
var scaledEnd = toIndexTime(end, this._index);
|
|
179
|
+
if (timeline.length > 0) {
|
|
180
|
+
var lastTimelineElement = timeline[timeline.length - 1];
|
|
181
|
+
var lastSegmentEnd = getIndexSegmentEnd(lastTimelineElement, null, this._scaledPeriodEnd);
|
|
182
|
+
var roundedEnd = lastSegmentEnd + segmentTimeRounding;
|
|
183
|
+
if (roundedEnd >= Math.min(scaledEnd, (_a = this._scaledPeriodEnd) !== null && _a !== void 0 ? _a : Infinity)) {
|
|
184
|
+
return false; // already loaded
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (this._scaledPeriodEnd === undefined) {
|
|
188
|
+
return (scaledEnd + segmentTimeRounding) > this._scaledPeriodStart ? undefined :
|
|
189
|
+
false;
|
|
190
|
+
}
|
|
191
|
+
var scaledStart = toIndexTime(start, this._index);
|
|
192
|
+
return (scaledStart - segmentTimeRounding) < this._scaledPeriodEnd &&
|
|
193
|
+
(scaledEnd + segmentTimeRounding) > this._scaledPeriodStart;
|
|
194
|
+
};
|
|
143
195
|
/**
|
|
144
196
|
* Returns true if a Segment returned by this index is still considered
|
|
145
197
|
* available.
|
|
@@ -188,9 +240,6 @@ var TimelineRepresentationIndex = /** @class */ (function () {
|
|
|
188
240
|
return error instanceof NetworkError &&
|
|
189
241
|
error.isHttpError(404);
|
|
190
242
|
};
|
|
191
|
-
TimelineRepresentationIndex.prototype.areSegmentsChronologicallyGenerated = function () {
|
|
192
|
-
return true;
|
|
193
|
-
};
|
|
194
243
|
/**
|
|
195
244
|
* Replace this RepresentationIndex with one from a new version of the
|
|
196
245
|
* Manifest.
|
|
@@ -253,7 +302,8 @@ var TimelineRepresentationIndex = /** @class */ (function () {
|
|
|
253
302
|
}
|
|
254
303
|
var lastTimelineElement = timeline[timeline.length - 1];
|
|
255
304
|
var lastTime = getIndexSegmentEnd(lastTimelineElement, null, this._scaledPeriodEnd);
|
|
256
|
-
|
|
305
|
+
var segmentTimeRounding = getSegmentTimeRoundingError(this._index.timescale);
|
|
306
|
+
return (lastTime + segmentTimeRounding) >= this._scaledPeriodEnd;
|
|
257
307
|
};
|
|
258
308
|
/**
|
|
259
309
|
* @returns {Boolean}
|
|
@@ -17,12 +17,9 @@
|
|
|
17
17
|
* In Javascript, numbers are encoded in a way that a floating number may be
|
|
18
18
|
* represented internally with a rounding error.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* rounding error to tell if the period is fulfilled with content.
|
|
20
|
+
* This function returns a small number allowing to accound for rounding many
|
|
21
|
+
* rounding errors.
|
|
23
22
|
* @param {number} timescale
|
|
24
|
-
* @param {number} lastSegmentEnd
|
|
25
|
-
* @param {number} periodEnd
|
|
26
23
|
* @returns {boolean}
|
|
27
24
|
*/
|
|
28
|
-
export
|
|
25
|
+
export declare function getSegmentTimeRoundingError(timescale: number): number;
|
|
@@ -18,15 +18,11 @@ import config from "../../../../../config";
|
|
|
18
18
|
* In Javascript, numbers are encoded in a way that a floating number may be
|
|
19
19
|
* represented internally with a rounding error.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* rounding error to tell if the period is fulfilled with content.
|
|
21
|
+
* This function returns a small number allowing to accound for rounding many
|
|
22
|
+
* rounding errors.
|
|
24
23
|
* @param {number} timescale
|
|
25
|
-
* @param {number} lastSegmentEnd
|
|
26
|
-
* @param {number} periodEnd
|
|
27
24
|
* @returns {boolean}
|
|
28
25
|
*/
|
|
29
|
-
export
|
|
30
|
-
|
|
31
|
-
return (lastSegmentEnd + scaledRoundingError) >= periodEnd;
|
|
26
|
+
export function getSegmentTimeRoundingError(timescale) {
|
|
27
|
+
return config.getCurrent().DEFAULT_MAXIMUM_TIME_ROUNDING_ERROR * timescale;
|
|
32
28
|
}
|
|
@@ -186,7 +186,7 @@ function getMaximumLastPosition(adaptationsPerType) {
|
|
|
186
186
|
var representations = adaptation.representations;
|
|
187
187
|
for (var _a = 0, representations_1 = representations; _a < representations_1.length; _a++) {
|
|
188
188
|
var representation = representations_1[_a];
|
|
189
|
-
var position = representation.index.
|
|
189
|
+
var position = representation.index.getLastAvailablePosition();
|
|
190
190
|
if (position !== null) {
|
|
191
191
|
allIndexAreEmpty = false;
|
|
192
192
|
if (typeof position === "number") {
|
|
@@ -30,12 +30,12 @@ export default function parseLocalManifest(localManifest) {
|
|
|
30
30
|
var periodIdGenerator = idGenerator();
|
|
31
31
|
var minimumPosition = localManifest.minimumPosition, maximumPosition = localManifest.maximumPosition, isFinished = localManifest.isFinished;
|
|
32
32
|
var parsedPeriods = localManifest.periods
|
|
33
|
-
.map(function (period) { return parsePeriod(period, { periodIdGenerator: periodIdGenerator
|
|
33
|
+
.map(function (period) { return parsePeriod(period, { periodIdGenerator: periodIdGenerator }); });
|
|
34
34
|
return { availabilityStartTime: 0,
|
|
35
35
|
expired: localManifest.expired,
|
|
36
36
|
transportType: "local",
|
|
37
37
|
isDynamic: !isFinished,
|
|
38
|
-
isLastPeriodKnown:
|
|
38
|
+
isLastPeriodKnown: true,
|
|
39
39
|
isLive: false,
|
|
40
40
|
uris: [],
|
|
41
41
|
timeBounds: { minimumSafePosition: minimumPosition !== null && minimumPosition !== void 0 ? minimumPosition : 0,
|
|
@@ -52,7 +52,6 @@ export default function parseLocalManifest(localManifest) {
|
|
|
52
52
|
* @returns {Object}
|
|
53
53
|
*/
|
|
54
54
|
function parsePeriod(period, ctxt) {
|
|
55
|
-
var isFinished = ctxt.isFinished;
|
|
56
55
|
var adaptationIdGenerator = idGenerator();
|
|
57
56
|
return {
|
|
58
57
|
id: "period-" + ctxt.periodIdGenerator(),
|
|
@@ -67,7 +66,7 @@ function parsePeriod(period, ctxt) {
|
|
|
67
66
|
adaps = [];
|
|
68
67
|
acc[type] = adaps;
|
|
69
68
|
}
|
|
70
|
-
adaps.push(parseAdaptation(ada, { adaptationIdGenerator: adaptationIdGenerator
|
|
69
|
+
adaps.push(parseAdaptation(ada, { adaptationIdGenerator: adaptationIdGenerator }));
|
|
71
70
|
return acc;
|
|
72
71
|
}, {}),
|
|
73
72
|
};
|
|
@@ -78,7 +77,6 @@ function parsePeriod(period, ctxt) {
|
|
|
78
77
|
* @returns {Object}
|
|
79
78
|
*/
|
|
80
79
|
function parseAdaptation(adaptation, ctxt) {
|
|
81
|
-
var isFinished = ctxt.isFinished;
|
|
82
80
|
var representationIdGenerator = idGenerator();
|
|
83
81
|
return {
|
|
84
82
|
id: "adaptation-" + ctxt.adaptationIdGenerator(),
|
|
@@ -87,7 +85,7 @@ function parseAdaptation(adaptation, ctxt) {
|
|
|
87
85
|
closedCaption: adaptation.closedCaption,
|
|
88
86
|
language: adaptation.language,
|
|
89
87
|
representations: adaptation.representations.map(function (representation) {
|
|
90
|
-
return parseRepresentation(representation, { representationIdGenerator: representationIdGenerator
|
|
88
|
+
return parseRepresentation(representation, { representationIdGenerator: representationIdGenerator });
|
|
91
89
|
}),
|
|
92
90
|
};
|
|
93
91
|
}
|
|
@@ -96,7 +94,6 @@ function parseAdaptation(adaptation, ctxt) {
|
|
|
96
94
|
* @returns {Object}
|
|
97
95
|
*/
|
|
98
96
|
function parseRepresentation(representation, ctxt) {
|
|
99
|
-
var isFinished = ctxt.isFinished;
|
|
100
97
|
var id = "representation-" + ctxt.representationIdGenerator();
|
|
101
98
|
var contentProtections = representation.contentProtections === undefined ?
|
|
102
99
|
undefined :
|
|
@@ -106,7 +103,7 @@ function parseRepresentation(representation, ctxt) {
|
|
|
106
103
|
width: representation.width,
|
|
107
104
|
codecs: representation.codecs,
|
|
108
105
|
mimeType: representation.mimeType,
|
|
109
|
-
index: new LocalRepresentationIndex(representation.index, id
|
|
106
|
+
index: new LocalRepresentationIndex(representation.index, id), contentProtections: contentProtections };
|
|
110
107
|
}
|
|
111
108
|
/**
|
|
112
109
|
* Translate Local Manifest's `contentProtections` attribute to the one defined
|
|
@@ -18,8 +18,7 @@ import { ILocalIndex } from "./types";
|
|
|
18
18
|
export default class LocalRepresentationIndex implements IRepresentationIndex {
|
|
19
19
|
private _index;
|
|
20
20
|
private _representationId;
|
|
21
|
-
|
|
22
|
-
constructor(index: ILocalIndex, representationId: string, isFinished: boolean);
|
|
21
|
+
constructor(index: ILocalIndex, representationId: string);
|
|
23
22
|
/**
|
|
24
23
|
* @returns {Object}
|
|
25
24
|
*/
|
|
@@ -33,11 +32,29 @@ export default class LocalRepresentationIndex implements IRepresentationIndex {
|
|
|
33
32
|
/**
|
|
34
33
|
* @returns {Number|undefined}
|
|
35
34
|
*/
|
|
36
|
-
|
|
35
|
+
getFirstAvailablePosition(): number | undefined;
|
|
37
36
|
/**
|
|
38
37
|
* @returns {Number|undefined}
|
|
39
38
|
*/
|
|
40
|
-
|
|
39
|
+
getLastAvailablePosition(): number | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Returns the expected ending position of this RepresentationIndex.
|
|
42
|
+
* `undefined` if unknown.
|
|
43
|
+
* @returns {number|undefined}
|
|
44
|
+
*/
|
|
45
|
+
getEnd(): number | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Returns:
|
|
48
|
+
* - `true` if in the given time interval, at least one new segment is
|
|
49
|
+
* expected to be available in the future.
|
|
50
|
+
* - `false` either if all segments in that time interval are already
|
|
51
|
+
* available for download or if none will ever be available for it.
|
|
52
|
+
* - `undefined` when it is not possible to tell.
|
|
53
|
+
* @param {number} start
|
|
54
|
+
* @param {number} end
|
|
55
|
+
* @returns {boolean|undefined}
|
|
56
|
+
*/
|
|
57
|
+
awaitSegmentBetween(start: number, end: number): boolean | undefined;
|
|
41
58
|
/**
|
|
42
59
|
* @returns {Boolean}
|
|
43
60
|
*/
|
|
@@ -55,10 +72,6 @@ export default class LocalRepresentationIndex implements IRepresentationIndex {
|
|
|
55
72
|
* @returns {null}
|
|
56
73
|
*/
|
|
57
74
|
checkDiscontinuity(): null;
|
|
58
|
-
/**
|
|
59
|
-
* @returns {boolean}
|
|
60
|
-
*/
|
|
61
|
-
areSegmentsChronologicallyGenerated(): boolean;
|
|
62
75
|
/**
|
|
63
76
|
* @returns {Boolean}
|
|
64
77
|
*/
|