rx-player 3.27.0-dev.2022032100 → 3.27.0
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/CHANGELOG.md +5 -2
- package/VERSION +1 -1
- package/dist/_esm5.processed/compat/eme/custom_media_keys/old_webkit_media_keys.js +15 -11
- package/dist/_esm5.processed/compat/eme/custom_media_keys/webkit_media_keys.js +22 -6
- package/dist/_esm5.processed/compat/eme/generate_key_request.d.ts +4 -6
- package/dist/_esm5.processed/compat/eme/generate_key_request.js +4 -6
- package/dist/_esm5.processed/compat/get_start_date.d.ts +30 -0
- package/dist/_esm5.processed/compat/get_start_date.js +44 -0
- package/dist/_esm5.processed/compat/index.d.ts +2 -1
- package/dist/_esm5.processed/compat/index.js +2 -1
- package/dist/_esm5.processed/config.d.ts +1 -5
- package/dist/_esm5.processed/core/api/public_api.js +25 -25
- package/dist/_esm5.processed/core/decrypt/content_decryptor.js +11 -3
- package/dist/_esm5.processed/core/decrypt/create_or_load_session.js +1 -1
- package/dist/_esm5.processed/core/decrypt/create_session.d.ts +3 -1
- package/dist/_esm5.processed/core/decrypt/create_session.js +15 -5
- package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.d.ts +94 -1
- package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.js +237 -96
- package/dist/_esm5.processed/core/segment_buffers/garbage_collector.js +4 -1
- package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +2 -1
- package/dist/_esm5.processed/core/stream/period/period_stream.js +9 -3
- package/dist/_esm5.processed/core/stream/representation/append_segment_to_buffer.js +4 -3
- package/dist/_esm5.processed/core/stream/representation/force_garbage_collection.js +3 -2
- package/dist/_esm5.processed/core/stream/representation/get_buffer_status.d.ts +2 -2
- package/dist/_esm5.processed/core/stream/representation/get_buffer_status.js +9 -3
- package/dist/_esm5.processed/core/stream/representation/get_needed_segments.d.ts +11 -1
- package/dist/_esm5.processed/core/stream/representation/get_needed_segments.js +27 -45
- package/dist/_esm5.processed/core/stream/representation/representation_stream.js +6 -4
- package/dist/_esm5.processed/default_config.d.ts +2 -35
- package/dist/_esm5.processed/default_config.js +2 -35
- package/dist/_esm5.processed/transports/dash/add_segment_integrity_checks_to_loader.js +39 -38
- package/dist/_esm5.processed/utils/reference.js +0 -2
- package/dist/_esm5.processed/utils/task_canceller.d.ts +8 -1
- package/dist/_esm5.processed/utils/task_canceller.js +9 -1
- package/dist/rx-player.js +927 -587
- package/dist/rx-player.min.js +1 -1
- package/package.json +1 -1
- package/sonar-project.properties +1 -1
- package/src/compat/eme/custom_media_keys/old_webkit_media_keys.ts +16 -12
- package/src/compat/eme/custom_media_keys/webkit_media_keys.ts +21 -8
- package/src/compat/eme/generate_key_request.ts +4 -6
- package/src/compat/get_start_date.ts +48 -0
- package/src/compat/index.ts +2 -0
- package/src/core/api/public_api.ts +23 -27
- package/src/core/decrypt/content_decryptor.ts +15 -4
- package/src/core/decrypt/create_or_load_session.ts +4 -1
- package/src/core/decrypt/create_session.ts +23 -9
- package/src/core/decrypt/utils/loaded_sessions_store.ts +254 -102
- package/src/core/segment_buffers/garbage_collector.ts +4 -0
- package/src/core/stream/orchestrator/stream_orchestrator.ts +2 -1
- package/src/core/stream/period/period_stream.ts +9 -4
- package/src/core/stream/representation/append_segment_to_buffer.ts +17 -13
- package/src/core/stream/representation/force_garbage_collection.ts +4 -1
- package/src/core/stream/representation/get_buffer_status.ts +21 -13
- package/src/core/stream/representation/get_needed_segments.ts +40 -55
- package/src/core/stream/representation/representation_stream.ts +6 -4
- package/src/default_config.ts +20 -57
- package/src/transports/dash/add_segment_integrity_checks_to_loader.ts +41 -44
- package/src/utils/reference.ts +0 -2
- package/src/utils/task_canceller.ts +16 -1
|
@@ -55,8 +55,8 @@ export default function getBufferStatus(content, wantedStartPosition, playbackOb
|
|
|
55
55
|
/** Callback allowing to retrieve a segment's history in the buffer. */
|
|
56
56
|
var getBufferedHistory = segmentBuffer.getSegmentHistory.bind(segmentBuffer);
|
|
57
57
|
/** List of segments we will need to download. */
|
|
58
|
-
var _b = getNeededSegments({ content: content, bufferedSegments: bufferedSegments, currentPlaybackTime: currentPlaybackTime, fastSwitchThreshold: fastSwitchThreshold, getBufferedHistory: getBufferedHistory, neededRange: neededRange, segmentsBeingPushed: segmentsBeingPushed, maxBufferSize: maxBufferSize }),
|
|
59
|
-
var prioritizedNeededSegments =
|
|
58
|
+
var _b = getNeededSegments({ content: content, bufferedSegments: bufferedSegments, currentPlaybackTime: currentPlaybackTime, fastSwitchThreshold: fastSwitchThreshold, getBufferedHistory: getBufferedHistory, neededRange: neededRange, segmentsBeingPushed: segmentsBeingPushed, maxBufferSize: maxBufferSize }), segmentsToLoad = _b.segmentsToLoad, segmentsOnHold = _b.segmentsOnHold, isBufferFull = _b.isBufferFull;
|
|
59
|
+
var prioritizedNeededSegments = segmentsToLoad.map(function (segment) { return ({
|
|
60
60
|
priority: getSegmentPriority(segment.time, wantedStartPosition),
|
|
61
61
|
segment: segment,
|
|
62
62
|
}); });
|
|
@@ -68,7 +68,8 @@ export default function getBufferStatus(content, wantedStartPosition, playbackOb
|
|
|
68
68
|
var lastPosition = representation.index.getLastPosition();
|
|
69
69
|
if (!representation.index.isInitialized() ||
|
|
70
70
|
period.end === undefined ||
|
|
71
|
-
prioritizedNeededSegments.length > 0
|
|
71
|
+
prioritizedNeededSegments.length > 0 ||
|
|
72
|
+
segmentsOnHold.length > 0) {
|
|
72
73
|
hasFinishedLoading = false;
|
|
73
74
|
}
|
|
74
75
|
else {
|
|
@@ -112,6 +113,11 @@ export default function getBufferStatus(content, wantedStartPosition, playbackOb
|
|
|
112
113
|
if (segmentsBeingPushed.length > 0) {
|
|
113
114
|
nextSegmentStart = Math.min.apply(Math, segmentsBeingPushed.map(function (info) { return info.segment.time; }));
|
|
114
115
|
}
|
|
116
|
+
if (segmentsOnHold.length > 0) {
|
|
117
|
+
nextSegmentStart = nextSegmentStart !== null ?
|
|
118
|
+
Math.min(nextSegmentStart, segmentsOnHold[0].time) :
|
|
119
|
+
segmentsOnHold[0].time;
|
|
120
|
+
}
|
|
115
121
|
if (prioritizedNeededSegments.length > 0) {
|
|
116
122
|
nextSegmentStart = nextSegmentStart !== null ?
|
|
117
123
|
Math.min(nextSegmentStart, prioritizedNeededSegments[0].segment.time) :
|
|
@@ -65,7 +65,17 @@ export interface IGetNeededSegmentsArguments {
|
|
|
65
65
|
getBufferedHistory: (context: IChunkContext) => IBufferedHistoryEntry[];
|
|
66
66
|
}
|
|
67
67
|
interface INeededSegments {
|
|
68
|
-
|
|
68
|
+
/** Segments that should be loaded right now, by chronological order. */
|
|
69
|
+
segmentsToLoad: ISegment[];
|
|
70
|
+
/**
|
|
71
|
+
* Segments that should be loaded, but not right now, due to some other
|
|
72
|
+
* constraints, such as memory limitations.
|
|
73
|
+
*/
|
|
74
|
+
segmentsOnHold: ISegment[];
|
|
75
|
+
/**
|
|
76
|
+
* If `true` the buffer is currently full according to the given limits.
|
|
77
|
+
* Memory should be freed if possible, for example by cleaning the buffers.
|
|
78
|
+
*/
|
|
69
79
|
isBufferFull: boolean;
|
|
70
80
|
}
|
|
71
81
|
/**
|
|
@@ -32,8 +32,6 @@ export default function getNeededSegments(_a) {
|
|
|
32
32
|
var bufferedSegments = _a.bufferedSegments, content = _a.content, currentPlaybackTime = _a.currentPlaybackTime, fastSwitchThreshold = _a.fastSwitchThreshold, getBufferedHistory = _a.getBufferedHistory, neededRange = _a.neededRange, segmentsBeingPushed = _a.segmentsBeingPushed, maxBufferSize = _a.maxBufferSize;
|
|
33
33
|
var representation = content.representation;
|
|
34
34
|
var availableBufferSize = getAvailableBufferSize(bufferedSegments, segmentsBeingPushed, maxBufferSize);
|
|
35
|
-
// Current buffer length in seconds
|
|
36
|
-
var bufferLength = getBufferLength(bufferedSegments, segmentsBeingPushed);
|
|
37
35
|
var availableSegmentsForRange = representation.index
|
|
38
36
|
.getSegments(neededRange.start, neededRange.end - neededRange.start);
|
|
39
37
|
// Remove from `bufferedSegments` any segments we would prefer to replace:
|
|
@@ -63,15 +61,16 @@ export default function getNeededSegments(_a) {
|
|
|
63
61
|
}
|
|
64
62
|
return true;
|
|
65
63
|
});
|
|
66
|
-
var _b = config.getCurrent(), MINIMUM_SEGMENT_SIZE = _b.MINIMUM_SEGMENT_SIZE,
|
|
67
|
-
var
|
|
64
|
+
var _b = config.getCurrent(), MINIMUM_SEGMENT_SIZE = _b.MINIMUM_SEGMENT_SIZE, MIN_BUFFER_AHEAD = _b.MIN_BUFFER_AHEAD;
|
|
65
|
+
var shouldStopLoadingSegments = false;
|
|
68
66
|
/**
|
|
69
67
|
* Epsilon compensating for rounding errors when comparing the start and end
|
|
70
68
|
* time of multiple segments.
|
|
71
69
|
*/
|
|
72
70
|
var ROUNDING_ERROR = Math.min(1 / 60, MINIMUM_SEGMENT_SIZE);
|
|
73
71
|
var isBufferFull = false;
|
|
74
|
-
var
|
|
72
|
+
var segmentsOnHold = [];
|
|
73
|
+
var segmentsToLoad = availableSegmentsForRange.filter(function (segment) {
|
|
75
74
|
var contentObject = objectAssign({ segment: segment }, content);
|
|
76
75
|
// First, check that the segment is not already being pushed
|
|
77
76
|
if (segmentsBeingPushed.length > 0) {
|
|
@@ -85,17 +84,8 @@ export default function getNeededSegments(_a) {
|
|
|
85
84
|
if (segment.isInit) {
|
|
86
85
|
return true; // never skip initialization segments
|
|
87
86
|
}
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
// That we cannot download atleast till
|
|
91
|
-
// NeededRange.Start ( current position ) + a CONST
|
|
92
|
-
// Then the buffer is full
|
|
93
|
-
if (time < neededRange.start + MIN_BUFFER_DISTANCE_BEFORE_CLEAN_UP) {
|
|
94
|
-
isBufferFull = true;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
if (isMemorySaturated &&
|
|
98
|
-
bufferLength > MIN_BUFFER_LENGTH) {
|
|
87
|
+
if (shouldStopLoadingSegments) {
|
|
88
|
+
segmentsOnHold.push(segment);
|
|
99
89
|
return false;
|
|
100
90
|
}
|
|
101
91
|
if (segment.complete && duration < MINIMUM_SEGMENT_SIZE) {
|
|
@@ -138,27 +128,34 @@ export default function getNeededSegments(_a) {
|
|
|
138
128
|
}
|
|
139
129
|
}
|
|
140
130
|
}
|
|
131
|
+
var estimatedSegmentSize = (duration * content.representation.bitrate) / 8000;
|
|
132
|
+
if (availableBufferSize - estimatedSegmentSize < 0) {
|
|
133
|
+
isBufferFull = true;
|
|
134
|
+
if (time > neededRange.start + MIN_BUFFER_AHEAD) {
|
|
135
|
+
shouldStopLoadingSegments = true;
|
|
136
|
+
segmentsOnHold.push(segment);
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
141
140
|
// check if there is an hole in place of the segment currently
|
|
142
141
|
for (var i = 0; i < segmentsToKeep.length; i++) {
|
|
143
142
|
var completeSeg = segmentsToKeep[i];
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
getLastContiguousSegment(segmentsToKeep, i).end <
|
|
143
|
+
// For the first already-loaded segment, take the first one ending after
|
|
144
|
+
// this one' s start
|
|
145
|
+
if ((completeSeg.end + ROUNDING_ERROR) > time) {
|
|
146
|
+
var shouldLoad = completeSeg.start > time + ROUNDING_ERROR ||
|
|
147
|
+
getLastContiguousSegment(segmentsToKeep, i).end <
|
|
148
|
+
end - ROUNDING_ERROR;
|
|
149
|
+
if (shouldLoad) {
|
|
150
|
+
availableBufferSize -= estimatedSegmentSize;
|
|
151
|
+
}
|
|
152
|
+
return shouldLoad;
|
|
149
153
|
}
|
|
150
154
|
}
|
|
151
|
-
var estimatedSegmentSize = (duration * content.representation.bitrate) / 8000;
|
|
152
|
-
if (availableBufferSize - estimatedSegmentSize < 0 &&
|
|
153
|
-
bufferLength > MIN_BUFFER_LENGTH) {
|
|
154
|
-
isMemorySaturated = true;
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
155
|
availableBufferSize -= estimatedSegmentSize;
|
|
158
|
-
bufferLength += duration;
|
|
159
156
|
return true;
|
|
160
157
|
});
|
|
161
|
-
return {
|
|
158
|
+
return { segmentsToLoad: segmentsToLoad, segmentsOnHold: segmentsOnHold, isBufferFull: isBufferFull };
|
|
162
159
|
}
|
|
163
160
|
/**
|
|
164
161
|
* Compute the estimated available buffer size in memory in kilobytes
|
|
@@ -178,28 +175,13 @@ function getAvailableBufferSize(bufferedSegments, segmentsBeingPushed, maxVideoB
|
|
|
178
175
|
}, 0);
|
|
179
176
|
return bufferedSegments.reduce(function (size, chunk) {
|
|
180
177
|
if (chunk.chunkSize !== undefined) {
|
|
181
|
-
return size - (chunk.chunkSize /
|
|
178
|
+
return size - (chunk.chunkSize / 1000);
|
|
182
179
|
}
|
|
183
180
|
else {
|
|
184
181
|
return size;
|
|
185
182
|
}
|
|
186
183
|
}, availableBufferSize);
|
|
187
184
|
}
|
|
188
|
-
/**
|
|
189
|
-
* Compute the length of the buffer in seconds
|
|
190
|
-
* @param bufferedSegments
|
|
191
|
-
* @param segmentsBeingPushed
|
|
192
|
-
* @returns bufferLength in seconds
|
|
193
|
-
*/
|
|
194
|
-
function getBufferLength(bufferedSegments, segmentsBeingPushed) {
|
|
195
|
-
var bufferLength = bufferedSegments.reduce(function (length, segment) {
|
|
196
|
-
return length + (segment.end - segment.start);
|
|
197
|
-
}, 0);
|
|
198
|
-
var bufferBeingPushed = segmentsBeingPushed.reduce(function (length, segment) {
|
|
199
|
-
return length + segment.segment.duration;
|
|
200
|
-
}, 0);
|
|
201
|
-
return bufferLength + bufferBeingPushed;
|
|
202
|
-
}
|
|
203
185
|
/**
|
|
204
186
|
* From the given array of buffered chunks (`bufferedSegments`) returns the last
|
|
205
187
|
* buffered chunk contiguous with the one at the `startIndex` index given.
|
|
@@ -166,10 +166,12 @@ export default function RepresentationStream(_a) {
|
|
|
166
166
|
var UPTO_CURRENT_POSITION_CLEANUP = config.getCurrent().UPTO_CURRENT_POSITION_CLEANUP;
|
|
167
167
|
if (status.isBufferFull) {
|
|
168
168
|
var gcedPosition = Math.max(0, wantedStartPosition - UPTO_CURRENT_POSITION_CLEANUP);
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
if (gcedPosition > 0) {
|
|
170
|
+
bufferRemoval = segmentBuffer
|
|
171
|
+
.removeBuffer(0, gcedPosition)
|
|
172
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
173
|
+
.pipe(ignoreElements());
|
|
174
|
+
}
|
|
173
175
|
}
|
|
174
176
|
return status.shouldRefreshManifest ?
|
|
175
177
|
observableConcat(observableOf(EVENTS.needsManifestRefresh()), bufferStatusEvt, bufferRemoval) :
|
|
@@ -934,33 +934,6 @@ declare const DEFAULT_CONFIG: {
|
|
|
934
934
|
* This wasn't battle-tested however.
|
|
935
935
|
*/
|
|
936
936
|
EME_MAX_STORED_PERSISTENT_SESSION_INFORMATION: number;
|
|
937
|
-
/**
|
|
938
|
-
* Attempts to closing a MediaKeySession can fail, most likely because the
|
|
939
|
-
* MediaKeySession was not initialized yet.
|
|
940
|
-
* When we consider that we're in one of these case, we will retry to close it.
|
|
941
|
-
*
|
|
942
|
-
* To avoid going into an infinite loop of retry, this number indicates a
|
|
943
|
-
* maximum number of attemps we're going to make (`0` meaning no retry at all,
|
|
944
|
-
* `1` only one retry and so on).
|
|
945
|
-
*/
|
|
946
|
-
EME_SESSION_CLOSING_MAX_RETRY: number;
|
|
947
|
-
/**
|
|
948
|
-
* When closing a MediaKeySession failed due to the reasons explained for the
|
|
949
|
-
* `EME_SESSION_CLOSING_MAX_RETRY` config property, we may (among other
|
|
950
|
-
* triggers) choose to wait a delay raising exponentially at each retry before
|
|
951
|
-
* that new attempt.
|
|
952
|
-
* This value indicates the initial value for this delay, in milliseconds.
|
|
953
|
-
*/
|
|
954
|
-
EME_SESSION_CLOSING_INITIAL_DELAY: number;
|
|
955
|
-
/**
|
|
956
|
-
* When closing a MediaKeySession failed due to the reasons explained for the
|
|
957
|
-
* `EME_SESSION_CLOSING_MAX_RETRY` config property, we may (among other
|
|
958
|
-
* triggers) choose to wait a delay raising exponentially at each retry before
|
|
959
|
-
* that new attempt.
|
|
960
|
-
* This value indicates the maximum possible value for this delay, in
|
|
961
|
-
* milliseconds.
|
|
962
|
-
*/
|
|
963
|
-
EME_SESSION_CLOSING_MAX_DELAY: number;
|
|
964
937
|
/**
|
|
965
938
|
* After loading a persistent MediaKeySession, the RxPlayer needs to ensure
|
|
966
939
|
* that its keys still allow to decrypt a content.
|
|
@@ -1092,17 +1065,11 @@ declare const DEFAULT_CONFIG: {
|
|
|
1092
1065
|
* there can be in that history.
|
|
1093
1066
|
*/
|
|
1094
1067
|
BUFFERED_HISTORY_MAXIMUM_ENTRIES: number;
|
|
1095
|
-
/**
|
|
1096
|
-
* Minimum buffer (in seconds) we should have, regardless of memory
|
|
1097
|
-
* constraints
|
|
1098
|
-
*/
|
|
1099
|
-
MIN_BUFFER_LENGTH: number;
|
|
1100
1068
|
/**
|
|
1101
1069
|
* Minimum buffer in seconds ahead relative to current time
|
|
1102
|
-
* we should be able to download
|
|
1103
|
-
* Before trying to agressively free up memory
|
|
1070
|
+
* we should be able to download, even in cases of saturated memory.
|
|
1104
1071
|
*/
|
|
1105
|
-
|
|
1072
|
+
MIN_BUFFER_AHEAD: number;
|
|
1106
1073
|
/**
|
|
1107
1074
|
* Distance in seconds behind the current position
|
|
1108
1075
|
* the player will free up to in the case we agressively free up memory
|
|
@@ -978,33 +978,6 @@ var DEFAULT_CONFIG = {
|
|
|
978
978
|
* This wasn't battle-tested however.
|
|
979
979
|
*/
|
|
980
980
|
EME_MAX_STORED_PERSISTENT_SESSION_INFORMATION: 1000,
|
|
981
|
-
/**
|
|
982
|
-
* Attempts to closing a MediaKeySession can fail, most likely because the
|
|
983
|
-
* MediaKeySession was not initialized yet.
|
|
984
|
-
* When we consider that we're in one of these case, we will retry to close it.
|
|
985
|
-
*
|
|
986
|
-
* To avoid going into an infinite loop of retry, this number indicates a
|
|
987
|
-
* maximum number of attemps we're going to make (`0` meaning no retry at all,
|
|
988
|
-
* `1` only one retry and so on).
|
|
989
|
-
*/
|
|
990
|
-
EME_SESSION_CLOSING_MAX_RETRY: 5,
|
|
991
|
-
/**
|
|
992
|
-
* When closing a MediaKeySession failed due to the reasons explained for the
|
|
993
|
-
* `EME_SESSION_CLOSING_MAX_RETRY` config property, we may (among other
|
|
994
|
-
* triggers) choose to wait a delay raising exponentially at each retry before
|
|
995
|
-
* that new attempt.
|
|
996
|
-
* This value indicates the initial value for this delay, in milliseconds.
|
|
997
|
-
*/
|
|
998
|
-
EME_SESSION_CLOSING_INITIAL_DELAY: 100,
|
|
999
|
-
/**
|
|
1000
|
-
* When closing a MediaKeySession failed due to the reasons explained for the
|
|
1001
|
-
* `EME_SESSION_CLOSING_MAX_RETRY` config property, we may (among other
|
|
1002
|
-
* triggers) choose to wait a delay raising exponentially at each retry before
|
|
1003
|
-
* that new attempt.
|
|
1004
|
-
* This value indicates the maximum possible value for this delay, in
|
|
1005
|
-
* milliseconds.
|
|
1006
|
-
*/
|
|
1007
|
-
EME_SESSION_CLOSING_MAX_DELAY: 1000,
|
|
1008
981
|
/**
|
|
1009
982
|
* After loading a persistent MediaKeySession, the RxPlayer needs to ensure
|
|
1010
983
|
* that its keys still allow to decrypt a content.
|
|
@@ -1124,17 +1097,11 @@ var DEFAULT_CONFIG = {
|
|
|
1124
1097
|
* there can be in that history.
|
|
1125
1098
|
*/
|
|
1126
1099
|
BUFFERED_HISTORY_MAXIMUM_ENTRIES: 200,
|
|
1127
|
-
/**
|
|
1128
|
-
* Minimum buffer (in seconds) we should have, regardless of memory
|
|
1129
|
-
* constraints
|
|
1130
|
-
*/
|
|
1131
|
-
MIN_BUFFER_LENGTH: 5,
|
|
1132
1100
|
/**
|
|
1133
1101
|
* Minimum buffer in seconds ahead relative to current time
|
|
1134
|
-
* we should be able to download
|
|
1135
|
-
* Before trying to agressively free up memory
|
|
1102
|
+
* we should be able to download, even in cases of saturated memory.
|
|
1136
1103
|
*/
|
|
1137
|
-
|
|
1104
|
+
MIN_BUFFER_AHEAD: 5,
|
|
1138
1105
|
/**
|
|
1139
1106
|
* Distance in seconds behind the current position
|
|
1140
1107
|
* the player will free up to in the case we agressively free up memory
|
|
@@ -36,53 +36,54 @@ import inferSegmentContainer from "../utils/infer_segment_container";
|
|
|
36
36
|
*/
|
|
37
37
|
export default function addSegmentIntegrityChecks(segmentLoader) {
|
|
38
38
|
return function (url, content, initialCancelSignal, callbacks) {
|
|
39
|
-
return new Promise(function (
|
|
40
|
-
var
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
* If the data's seems to be corrupted, cancel the loading task and reject
|
|
48
|
-
* with an `INTEGRITY_ERROR` error.
|
|
49
|
-
* @param {*} data
|
|
50
|
-
*/
|
|
51
|
-
function cancelAndRejectOnBadIntegrity(data) {
|
|
52
|
-
if (!(data instanceof Array) && !(data instanceof Uint8Array) ||
|
|
53
|
-
inferSegmentContainer(content.adaptation.type, content.representation) !== "mp4") {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
try {
|
|
57
|
-
checkISOBMFFIntegrity(new Uint8Array(data), content.segment.isInit);
|
|
58
|
-
}
|
|
59
|
-
catch (err) {
|
|
60
|
-
unregisterCancelLstnr();
|
|
61
|
-
canceller.cancel();
|
|
62
|
-
rej(err);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
segmentLoader(url, content, canceller.signal, __assign(__assign({}, callbacks), { onNewChunk: function (data) {
|
|
66
|
-
cancelAndRejectOnBadIntegrity(data);
|
|
67
|
-
if (!canceller.isUsed) {
|
|
39
|
+
return new Promise(function (resolve, reject) {
|
|
40
|
+
var requestCanceller = new TaskCanceller({ cancelOn: initialCancelSignal });
|
|
41
|
+
// Reject the `CancellationError` when `requestCanceller`'s signal emits
|
|
42
|
+
// `stopRejectingOnCancel` here is a function allowing to stop this mechanism
|
|
43
|
+
var stopRejectingOnCancel = requestCanceller.signal.register(reject);
|
|
44
|
+
segmentLoader(url, content, requestCanceller.signal, __assign(__assign({}, callbacks), { onNewChunk: function (data) {
|
|
45
|
+
try {
|
|
46
|
+
trowOnIntegrityError(data);
|
|
68
47
|
callbacks.onNewChunk(data);
|
|
69
48
|
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
// Do not reject with a `CancellationError` after cancelling the request
|
|
51
|
+
stopRejectingOnCancel();
|
|
52
|
+
// Cancel the request
|
|
53
|
+
requestCanceller.cancel();
|
|
54
|
+
// Reject with thrown error
|
|
55
|
+
reject(err);
|
|
56
|
+
}
|
|
70
57
|
} })).then(function (info) {
|
|
71
|
-
if (
|
|
58
|
+
if (requestCanceller.isUsed) {
|
|
72
59
|
return;
|
|
73
60
|
}
|
|
74
|
-
|
|
61
|
+
stopRejectingOnCancel();
|
|
75
62
|
if (info.resultType === "segment-loaded") {
|
|
76
|
-
|
|
63
|
+
try {
|
|
64
|
+
trowOnIntegrityError(info.resultData.responseData);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
reject(err);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
77
70
|
}
|
|
78
|
-
|
|
71
|
+
resolve(info);
|
|
79
72
|
}, function (error) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
unregisterCancelLstnr();
|
|
83
|
-
rej(error);
|
|
84
|
-
}
|
|
73
|
+
stopRejectingOnCancel();
|
|
74
|
+
reject(error);
|
|
85
75
|
});
|
|
86
76
|
});
|
|
77
|
+
/**
|
|
78
|
+
* If the data's seems to be corrupted, throws an `INTEGRITY_ERROR` error.
|
|
79
|
+
* @param {*} data
|
|
80
|
+
*/
|
|
81
|
+
function trowOnIntegrityError(data) {
|
|
82
|
+
if (!(data instanceof ArrayBuffer) && !(data instanceof Uint8Array) ||
|
|
83
|
+
inferSegmentContainer(content.adaptation.type, content.representation) !== "mp4") {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
checkISOBMFFIntegrity(new Uint8Array(data), content.segment.isInit);
|
|
87
|
+
}
|
|
87
88
|
};
|
|
88
89
|
}
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import { Observable, } from "rxjs";
|
|
17
|
-
import log from "../log";
|
|
18
17
|
/**
|
|
19
18
|
* Create an `ISharedReference` object encapsulating the mutable `initialValue`
|
|
20
19
|
* value of type T.
|
|
@@ -61,7 +60,6 @@ export function createSharedReference(initialValue) {
|
|
|
61
60
|
throw new Error("Finished shared references cannot be updated");
|
|
62
61
|
}
|
|
63
62
|
else {
|
|
64
|
-
log.error("Finished shared references cannot be updated");
|
|
65
63
|
return;
|
|
66
64
|
}
|
|
67
65
|
}
|
|
@@ -131,8 +131,15 @@ export default class TaskCanceller {
|
|
|
131
131
|
* Creates a new `TaskCanceller`, with its own `CancellationSignal` created
|
|
132
132
|
* as its `signal` provide.
|
|
133
133
|
* You can then pass this property to async task you wish to be cancellable.
|
|
134
|
+
* @param {Object|undefined} options
|
|
134
135
|
*/
|
|
135
|
-
constructor(
|
|
136
|
+
constructor(options?: {
|
|
137
|
+
/**
|
|
138
|
+
* If set the TaskCanceller created here will automatically be triggered
|
|
139
|
+
* when that signal emits.
|
|
140
|
+
*/
|
|
141
|
+
cancelOn?: CancellationSignal | undefined;
|
|
142
|
+
} | undefined);
|
|
136
143
|
/**
|
|
137
144
|
* "Trigger" the `TaskCanceller`, notify through its associated
|
|
138
145
|
* `CancellationSignal` (its `signal` property) that a task should be aborted.
|
|
@@ -132,12 +132,20 @@ var TaskCanceller = /** @class */ (function () {
|
|
|
132
132
|
* Creates a new `TaskCanceller`, with its own `CancellationSignal` created
|
|
133
133
|
* as its `signal` provide.
|
|
134
134
|
* You can then pass this property to async task you wish to be cancellable.
|
|
135
|
+
* @param {Object|undefined} options
|
|
135
136
|
*/
|
|
136
|
-
function TaskCanceller() {
|
|
137
|
+
function TaskCanceller(options) {
|
|
138
|
+
var _this = this;
|
|
137
139
|
var _a = createCancellationFunctions(), trigger = _a[0], register = _a[1];
|
|
138
140
|
this.isUsed = false;
|
|
139
141
|
this._trigger = trigger;
|
|
140
142
|
this.signal = new CancellationSignal(register);
|
|
143
|
+
if ((options === null || options === void 0 ? void 0 : options.cancelOn) !== undefined) {
|
|
144
|
+
var unregisterParent = options.cancelOn.register(function () {
|
|
145
|
+
_this.cancel();
|
|
146
|
+
});
|
|
147
|
+
this.signal.register(unregisterParent);
|
|
148
|
+
}
|
|
141
149
|
}
|
|
142
150
|
/**
|
|
143
151
|
* "Trigger" the `TaskCanceller`, notify through its associated
|