rx-player 3.29.0-dev.2022090500 → 3.29.0-dev.2022091600
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 -1
- package/VERSION +1 -1
- package/dist/_esm5.processed/core/api/option_utils.js +7 -11
- package/dist/_esm5.processed/core/api/public_api.d.ts +4 -4
- package/dist/_esm5.processed/core/api/public_api.js +18 -19
- package/dist/_esm5.processed/core/api/{media_element_track_choice_manager.d.ts → tracks_management/media_element_track_choice_manager.d.ts} +2 -2
- package/dist/_esm5.processed/core/api/{media_element_track_choice_manager.js → tracks_management/media_element_track_choice_manager.js} +7 -4
- package/dist/_esm5.processed/core/api/{track_choice_manager.d.ts → tracks_management/track_choice_manager.d.ts} +2 -2
- package/dist/_esm5.processed/core/api/{track_choice_manager.js → tracks_management/track_choice_manager.js} +7 -7
- package/dist/_esm5.processed/core/api/{emit_seek_events.d.ts → utils.d.ts} +24 -1
- package/dist/_esm5.processed/core/api/{emit_seek_events.js → utils.js} +32 -1
- package/dist/_esm5.processed/core/decrypt/content_decryptor.d.ts +26 -0
- package/dist/_esm5.processed/core/decrypt/content_decryptor.js +101 -9
- package/dist/_esm5.processed/core/decrypt/session_events_listener.d.ts +15 -18
- package/dist/_esm5.processed/core/decrypt/session_events_listener.js +9 -7
- package/dist/_esm5.processed/core/decrypt/utils/check_key_statuses.d.ts +19 -22
- package/dist/_esm5.processed/core/decrypt/utils/check_key_statuses.js +87 -16
- package/dist/_esm5.processed/core/decrypt/utils/persistent_sessions_store.d.ts +1 -2
- package/dist/_esm5.processed/core/decrypt/utils/persistent_sessions_store.js +1 -2
- package/dist/_esm5.processed/core/fetchers/index.d.ts +2 -2
- package/dist/_esm5.processed/core/fetchers/segment/index.d.ts +2 -3
- package/dist/_esm5.processed/core/fetchers/segment/prioritized_segment_fetcher.d.ts +9 -9
- package/dist/_esm5.processed/core/fetchers/segment/prioritized_segment_fetcher.js +17 -15
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.d.ts +33 -40
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.js +156 -153
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher_creator.d.ts +3 -3
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher_creator.js +2 -2
- package/dist/_esm5.processed/core/fetchers/segment/task_prioritizer.d.ts +145 -0
- package/dist/_esm5.processed/core/fetchers/segment/task_prioritizer.js +325 -0
- package/dist/_esm5.processed/core/fetchers/utils/try_urls_with_backoff.d.ts +2 -2
- package/dist/_esm5.processed/core/fetchers/utils/try_urls_with_backoff.js +3 -3
- package/dist/_esm5.processed/core/init/create_media_source.d.ts +10 -0
- package/dist/_esm5.processed/core/init/create_media_source.js +1 -1
- package/dist/_esm5.processed/core/init/stall_avoider.d.ts +2 -1
- package/dist/_esm5.processed/core/init/stall_avoider.js +2 -1
- package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +1 -1
- package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +3 -3
- package/dist/_esm5.processed/core/segment_buffers/implementations/types.d.ts +6 -2
- package/dist/_esm5.processed/core/stream/orchestrator/{get_blacklisted_ranges.d.ts → get_time_ranges_for_content.d.ts} +1 -1
- package/dist/_esm5.processed/core/stream/orchestrator/{get_blacklisted_ranges.js → get_time_ranges_for_content.js} +1 -1
- package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +61 -19
- package/dist/_esm5.processed/core/stream/representation/downloading_queue.d.ts +8 -4
- package/dist/_esm5.processed/core/stream/representation/downloading_queue.js +200 -83
- package/dist/_esm5.processed/core/stream/types.d.ts +3 -1
- package/dist/_esm5.processed/errors/encrypted_media_error.d.ts +6 -1
- package/dist/_esm5.processed/errors/encrypted_media_error.js +4 -5
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/index.d.ts +1 -1
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/index.js +1 -1
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.d.ts +26 -0
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.js +60 -0
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.d.ts +6 -5
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.js +40 -9
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/remove_buffer_around_time.d.ts +3 -2
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/remove_buffer_around_time.js +7 -14
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/types.d.ts +1 -1
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/{thumbnail_loader.d.ts → video_thumbnail_loader.d.ts} +1 -13
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.js +331 -0
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader_error.d.ts +1 -2
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader_error.js +1 -2
- package/dist/_esm5.processed/features/initialize_features.js +2 -1
- package/dist/_esm5.processed/features/list/directfile.js +1 -1
- package/dist/_esm5.processed/features/types.d.ts +1 -1
- package/dist/_esm5.processed/manifest/index.d.ts +2 -2
- package/dist/_esm5.processed/public_types.d.ts +47 -0
- package/dist/_esm5.processed/utils/reference.d.ts +23 -3
- package/dist/_esm5.processed/utils/reference.js +23 -2
- package/dist/rx-player.js +1253 -1014
- package/dist/rx-player.min.js +1 -1
- package/package.json +1 -1
- package/sonar-project.properties +1 -1
- package/src/core/api/README.md +1 -1
- package/src/core/api/__tests__/{get_player_state.test.ts → utils.test.ts} +1 -1
- package/src/core/api/option_utils.ts +1 -5
- package/src/core/api/public_api.ts +15 -13
- package/src/core/api/{__tests__ → tracks_management/__tests__}/media_element_track_choice_manager.test.ts +0 -0
- package/src/core/api/{media_element_track_choice_manager.ts → tracks_management/media_element_track_choice_manager.ts} +10 -7
- package/src/core/api/{track_choice_manager.ts → tracks_management/track_choice_manager.ts} +9 -9
- package/src/core/api/{get_player_state.ts → utils.ts} +62 -11
- package/src/core/decrypt/content_decryptor.ts +112 -13
- package/src/core/decrypt/session_events_listener.ts +34 -30
- package/src/core/decrypt/utils/check_key_statuses.ts +89 -45
- package/src/core/decrypt/utils/persistent_sessions_store.ts +1 -2
- package/src/core/fetchers/index.ts +0 -12
- package/src/core/fetchers/segment/__tests__/task_prioritizer.test.ts +763 -0
- package/src/core/fetchers/segment/index.ts +0 -12
- package/src/core/fetchers/segment/prioritized_segment_fetcher.ts +40 -47
- package/src/core/fetchers/segment/segment_fetcher.ts +249 -268
- package/src/core/fetchers/segment/segment_fetcher_creator.ts +6 -7
- package/src/core/fetchers/segment/task_prioritizer.ts +460 -0
- package/src/core/fetchers/utils/try_urls_with_backoff.ts +3 -3
- package/src/core/init/create_media_source.ts +1 -1
- package/src/core/init/stall_avoider.ts +2 -1
- package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +1 -1
- package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +3 -3
- package/src/core/segment_buffers/implementations/types.ts +6 -2
- package/src/core/stream/orchestrator/{get_blacklisted_ranges.ts → get_time_ranges_for_content.ts} +1 -1
- package/src/core/stream/orchestrator/stream_orchestrator.ts +115 -56
- package/src/core/stream/representation/downloading_queue.ts +269 -142
- package/src/core/stream/types.ts +3 -1
- package/src/errors/encrypted_media_error.ts +20 -1
- package/src/experimental/tools/VideoThumbnailLoader/index.ts +1 -1
- package/src/experimental/tools/VideoThumbnailLoader/load_and_push_segment.ts +74 -0
- package/src/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.ts +50 -16
- package/src/experimental/tools/VideoThumbnailLoader/remove_buffer_around_time.ts +14 -21
- package/src/experimental/tools/VideoThumbnailLoader/types.ts +7 -4
- package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +407 -0
- package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader_error.ts +1 -2
- package/src/features/__tests__/initialize_features.test.ts +3 -1
- package/src/features/initialize_features.ts +2 -1
- package/src/features/list/__tests__/directfile.test.ts +1 -1
- package/src/features/list/directfile.ts +1 -1
- package/src/features/types.ts +1 -1
- package/src/manifest/index.ts +2 -0
- package/src/public_types.ts +53 -0
- package/src/utils/reference.ts +58 -4
- package/dist/_esm5.processed/core/api/get_player_state.d.ts +0 -28
- package/dist/_esm5.processed/core/api/get_player_state.js +0 -56
- package/dist/_esm5.processed/core/fetchers/segment/prioritizer.d.ts +0 -232
- package/dist/_esm5.processed/core/fetchers/segment/prioritizer.js +0 -422
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/create_request.d.ts +0 -29
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/create_request.js +0 -68
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/get_complete_segment_id.d.ts +0 -24
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/get_complete_segment_id.js +0 -29
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/get_content_infos.d.ts +0 -25
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/get_content_infos.js +0 -40
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/get_initialized_source_buffer.d.ts +0 -33
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/get_initialized_source_buffer.js +0 -124
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_segments.d.ts +0 -17
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_segments.js +0 -41
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/push_data.d.ts +0 -22
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/push_data.js +0 -21
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/thumbnail_loader.js +0 -212
- package/src/core/api/emit_seek_events.ts +0 -66
- package/src/core/fetchers/segment/__tests__/prioritizer.test.ts +0 -962
- package/src/core/fetchers/segment/prioritizer.ts +0 -558
- package/src/experimental/tools/VideoThumbnailLoader/create_request.ts +0 -113
- package/src/experimental/tools/VideoThumbnailLoader/get_complete_segment_id.ts +0 -34
- package/src/experimental/tools/VideoThumbnailLoader/get_content_infos.ts +0 -48
- package/src/experimental/tools/VideoThumbnailLoader/get_initialized_source_buffer.ts +0 -171
- package/src/experimental/tools/VideoThumbnailLoader/load_segments.ts +0 -69
- package/src/experimental/tools/VideoThumbnailLoader/push_data.ts +0 -48
- package/src/experimental/tools/VideoThumbnailLoader/thumbnail_loader.ts +0 -311
|
@@ -40,7 +40,7 @@ import EVENTS from "../events_generators";
|
|
|
40
40
|
import PeriodStream from "../period";
|
|
41
41
|
import ActivePeriodEmitter from "./active_period_emitter";
|
|
42
42
|
import areStreamsComplete from "./are_streams_complete";
|
|
43
|
-
import
|
|
43
|
+
import getTimeRangesForContent from "./get_time_ranges_for_content";
|
|
44
44
|
/**
|
|
45
45
|
* Create and manage the various Stream Observables needed for the content to
|
|
46
46
|
* play:
|
|
@@ -204,29 +204,43 @@ export default function StreamOrchestrator(content, playbackObserver, representa
|
|
|
204
204
|
}
|
|
205
205
|
return launchConsecutiveStreamsForPeriod(newInitialPeriod);
|
|
206
206
|
}));
|
|
207
|
-
// Free the buffer of undecipherable data
|
|
208
207
|
var handleDecipherabilityUpdate$ = fromEvent(manifest, "decipherabilityUpdate")
|
|
209
|
-
.pipe(mergeMap(
|
|
208
|
+
.pipe(mergeMap(onDecipherabilityUpdates));
|
|
209
|
+
return observableMerge(restartStreamsWhenOutOfBounds$, handleDecipherabilityUpdate$, launchConsecutiveStreamsForPeriod(basePeriod));
|
|
210
|
+
function onDecipherabilityUpdates(updates) {
|
|
210
211
|
var segmentBufferStatus = segmentBuffersStore.getStatus(bufferType);
|
|
211
212
|
var ofCurrentType = updates
|
|
212
213
|
.filter(function (update) { return update.adaptation.type === bufferType; });
|
|
213
214
|
if (ofCurrentType.length === 0 || segmentBufferStatus.type !== "initialized") {
|
|
214
215
|
return EMPTY; // no need to stop the current Streams.
|
|
215
216
|
}
|
|
216
|
-
var
|
|
217
|
+
var segmentBuffer = segmentBufferStatus.value;
|
|
218
|
+
var resettedContent = ofCurrentType.filter(function (update) {
|
|
219
|
+
return update.representation.decipherable === undefined;
|
|
220
|
+
});
|
|
221
|
+
var undecipherableContent = ofCurrentType.filter(function (update) {
|
|
217
222
|
return update.representation.decipherable === false;
|
|
218
223
|
});
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
224
|
+
/**
|
|
225
|
+
* Time ranges now containing undecipherable content.
|
|
226
|
+
* Those should first be removed and, depending on the platform, may
|
|
227
|
+
* need Supplementary actions as playback issues may remain even after
|
|
228
|
+
* removal.
|
|
229
|
+
*/
|
|
230
|
+
var undecipherableRanges = getTimeRangesForContent(segmentBuffer, undecipherableContent);
|
|
231
|
+
/**
|
|
232
|
+
* Time ranges now containing content whose decipherability status came
|
|
233
|
+
* back to being unknown.
|
|
234
|
+
* To simplify its handling, those are just removed from the buffer.
|
|
235
|
+
* Less considerations have to be taken than for the `undecipherableRanges`.
|
|
236
|
+
*/
|
|
237
|
+
var rangesToRemove = getTimeRangesForContent(segmentBuffer, resettedContent);
|
|
238
|
+
// First close all Stream currently active so they don't continue to
|
|
239
|
+
// load and push segments.
|
|
227
240
|
enableOutOfBoundsCheck = false;
|
|
228
241
|
destroyStreams$.next();
|
|
229
|
-
|
|
242
|
+
/** Remove from the `SegmentBuffer` all the concerned time ranges. */
|
|
243
|
+
var cleanOperations = __spreadArray(__spreadArray([], undecipherableRanges, true), rangesToRemove, true).map(function (_a) {
|
|
230
244
|
var start = _a.start, end = _a.end;
|
|
231
245
|
if (start >= end) {
|
|
232
246
|
return EMPTY;
|
|
@@ -235,15 +249,15 @@ export default function StreamOrchestrator(content, playbackObserver, representa
|
|
|
235
249
|
return fromCancellablePromise(canceller, function () {
|
|
236
250
|
return segmentBuffer.removeBuffer(start, end, canceller.signal);
|
|
237
251
|
}).pipe(ignoreElements());
|
|
238
|
-
})
|
|
252
|
+
});
|
|
253
|
+
return observableConcat.apply(void 0, __spreadArray(__spreadArray([], cleanOperations, false), [
|
|
239
254
|
// Schedule micro task before checking the last playback observation
|
|
240
255
|
// to reduce the risk of race conditions where the next observation
|
|
241
256
|
// was going to be emitted synchronously.
|
|
242
257
|
nextTickObs().pipe(ignoreElements()),
|
|
243
258
|
playbackObserver.getReference().asObservable().pipe(take(1), mergeMap(function (observation) {
|
|
244
259
|
var _a;
|
|
245
|
-
var
|
|
246
|
-
return observableConcat(observableOf(EVENTS.needsDecipherabilityFlush(observation.position.last, shouldAutoPlay, observation.duration)), observableDefer(function () {
|
|
260
|
+
var restartStream$ = observableDefer(function () {
|
|
247
261
|
var _a;
|
|
248
262
|
var lastPosition = (_a = observation.position.pending) !== null && _a !== void 0 ? _a : observation.position.last;
|
|
249
263
|
var newInitialPeriod = manifest.getPeriodForTime(lastPosition);
|
|
@@ -251,10 +265,17 @@ export default function StreamOrchestrator(content, playbackObserver, representa
|
|
|
251
265
|
throw new MediaError("MEDIA_TIME_NOT_FOUND", "The wanted position is not found in the Manifest.");
|
|
252
266
|
}
|
|
253
267
|
return launchConsecutiveStreamsForPeriod(newInitialPeriod);
|
|
254
|
-
})
|
|
268
|
+
});
|
|
269
|
+
if (needsFlushingAfterClean(observation, undecipherableRanges)) {
|
|
270
|
+
var shouldAutoPlay = !((_a = observation.paused.pending) !== null && _a !== void 0 ? _a : playbackObserver.getIsPaused());
|
|
271
|
+
return observableConcat(observableOf(EVENTS.needsDecipherabilityFlush(observation.position.last, shouldAutoPlay, observation.duration)), restartStream$);
|
|
272
|
+
}
|
|
273
|
+
else if (needsFlushingAfterClean(observation, rangesToRemove)) {
|
|
274
|
+
return observableConcat(observableOf(EVENTS.needsBufferFlush()), restartStream$);
|
|
275
|
+
}
|
|
276
|
+
return restartStream$;
|
|
255
277
|
}))], false));
|
|
256
|
-
}
|
|
257
|
-
return observableMerge(restartStreamsWhenOutOfBounds$, handleDecipherabilityUpdate$, launchConsecutiveStreamsForPeriod(basePeriod));
|
|
278
|
+
}
|
|
258
279
|
}
|
|
259
280
|
/**
|
|
260
281
|
* Create lazily consecutive PeriodStreams:
|
|
@@ -342,3 +363,24 @@ export default function StreamOrchestrator(content, playbackObserver, representa
|
|
|
342
363
|
return observableMerge(currentStream$, nextPeriodStream$, destroyAll$.pipe(ignoreElements()));
|
|
343
364
|
}
|
|
344
365
|
}
|
|
366
|
+
/**
|
|
367
|
+
* Returns `true` if low-level buffers have to be "flushed" after the given
|
|
368
|
+
* `cleanedRanges` time ranges have been removed from an audio or video
|
|
369
|
+
* SourceBuffer, to prevent playback issues.
|
|
370
|
+
* @param {Object} observation
|
|
371
|
+
* @param {Array.<Object>} cleanedRanges
|
|
372
|
+
* @returns {boolean}
|
|
373
|
+
*/
|
|
374
|
+
function needsFlushingAfterClean(observation, cleanedRanges) {
|
|
375
|
+
if (cleanedRanges.length === 0) {
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
var curPos = observation.position.last;
|
|
379
|
+
// Based on the playback direction, we just check whether we may encounter
|
|
380
|
+
// the corresponding ranges, without seeking or re-switching playback
|
|
381
|
+
// direction which is expected to lead to a low-level flush anyway.
|
|
382
|
+
// There's a 5 seconds security, just to be sure.
|
|
383
|
+
return observation.speed >= 0 ?
|
|
384
|
+
cleanedRanges[cleanedRanges.length - 1].end >= curPos - 5 :
|
|
385
|
+
cleanedRanges[0].start <= curPos + 5;
|
|
386
|
+
}
|
|
@@ -52,8 +52,12 @@ export default class DownloadingQueue<T> {
|
|
|
52
52
|
private _mediaSegmentRequest;
|
|
53
53
|
/** Interface used to load segments. */
|
|
54
54
|
private _segmentFetcher;
|
|
55
|
-
/**
|
|
56
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Emit the timescale anounced in the initialization segment once parsed.
|
|
57
|
+
* `undefined` when this is not yet known.
|
|
58
|
+
* `null` when no initialization segment or timescale exists.
|
|
59
|
+
*/
|
|
60
|
+
private _initSegmentInfoRef;
|
|
57
61
|
/**
|
|
58
62
|
* Some media segments might have been loaded and are only awaiting for the
|
|
59
63
|
* initialization segment to be parsed before being parsed themselves.
|
|
@@ -86,13 +90,13 @@ export default class DownloadingQueue<T> {
|
|
|
86
90
|
/**
|
|
87
91
|
* Returns the initialization segment currently being requested.
|
|
88
92
|
* Returns `null` if no initialization segment request is pending.
|
|
89
|
-
* @returns {Object}
|
|
93
|
+
* @returns {Object | null}
|
|
90
94
|
*/
|
|
91
95
|
getRequestedInitSegment(): ISegment | null;
|
|
92
96
|
/**
|
|
93
97
|
* Returns the media segment currently being requested.
|
|
94
98
|
* Returns `null` if no media segment request is pending.
|
|
95
|
-
* @returns {Object}
|
|
99
|
+
* @returns {Object | null}
|
|
96
100
|
*/
|
|
97
101
|
getRequestedMediaSegment(): ISegment | null;
|
|
98
102
|
/**
|
|
@@ -13,11 +13,12 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
16
|
+
import { defer as observableDefer, EMPTY, filter, finalize, merge as observableMerge, Observable, of as observableOf, share, switchMap, } from "rxjs";
|
|
17
17
|
import log from "../../../log";
|
|
18
18
|
import assert from "../../../utils/assert";
|
|
19
|
-
import assertUnreachable from "../../../utils/assert_unreachable";
|
|
20
19
|
import objectAssign from "../../../utils/object_assign";
|
|
20
|
+
import createSharedReference from "../../../utils/reference";
|
|
21
|
+
import TaskCanceller from "../../../utils/task_canceller";
|
|
21
22
|
/**
|
|
22
23
|
* Class scheduling segment downloads for a single Representation.
|
|
23
24
|
* @class DownloadingQueue
|
|
@@ -51,16 +52,16 @@ var DownloadingQueue = /** @class */ (function () {
|
|
|
51
52
|
this._initSegmentRequest = null;
|
|
52
53
|
this._mediaSegmentRequest = null;
|
|
53
54
|
this._segmentFetcher = segmentFetcher;
|
|
54
|
-
this.
|
|
55
|
+
this._initSegmentInfoRef = createSharedReference(undefined);
|
|
55
56
|
this._mediaSegmentsAwaitingInitMetadata = new Set();
|
|
56
57
|
if (!hasInitSegment) {
|
|
57
|
-
this.
|
|
58
|
+
this._initSegmentInfoRef.setValue(null);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
/**
|
|
61
62
|
* Returns the initialization segment currently being requested.
|
|
62
63
|
* Returns `null` if no initialization segment request is pending.
|
|
63
|
-
* @returns {Object}
|
|
64
|
+
* @returns {Object | null}
|
|
64
65
|
*/
|
|
65
66
|
DownloadingQueue.prototype.getRequestedInitSegment = function () {
|
|
66
67
|
return this._initSegmentRequest === null ? null :
|
|
@@ -69,7 +70,7 @@ var DownloadingQueue = /** @class */ (function () {
|
|
|
69
70
|
/**
|
|
70
71
|
* Returns the media segment currently being requested.
|
|
71
72
|
* Returns `null` if no media segment request is pending.
|
|
72
|
-
* @returns {Object}
|
|
73
|
+
* @returns {Object | null}
|
|
73
74
|
*/
|
|
74
75
|
DownloadingQueue.prototype.getRequestedMediaSegment = function () {
|
|
75
76
|
return this._mediaSegmentRequest === null ? null :
|
|
@@ -112,7 +113,7 @@ var DownloadingQueue = /** @class */ (function () {
|
|
|
112
113
|
return true;
|
|
113
114
|
}
|
|
114
115
|
if (currentSegmentRequest.priority !== nextItem.priority) {
|
|
115
|
-
_this._segmentFetcher.updatePriority(currentSegmentRequest.request
|
|
116
|
+
_this._segmentFetcher.updatePriority(currentSegmentRequest.request, nextItem.priority);
|
|
116
117
|
}
|
|
117
118
|
return false;
|
|
118
119
|
}), switchMap(function (_a) {
|
|
@@ -124,7 +125,7 @@ var DownloadingQueue = /** @class */ (function () {
|
|
|
124
125
|
var initSegmentRequest = _this._initSegmentRequest;
|
|
125
126
|
if (next.initSegment !== null && initSegmentRequest !== null) {
|
|
126
127
|
if (next.initSegment.priority !== initSegmentRequest.priority) {
|
|
127
|
-
_this._segmentFetcher.updatePriority(initSegmentRequest.request
|
|
128
|
+
_this._segmentFetcher.updatePriority(initSegmentRequest.request, next.initSegment.priority);
|
|
128
129
|
}
|
|
129
130
|
return false;
|
|
130
131
|
}
|
|
@@ -150,57 +151,153 @@ var DownloadingQueue = /** @class */ (function () {
|
|
|
150
151
|
var _this = this;
|
|
151
152
|
var segmentQueue = this._downloadQueue.getValue().segmentQueue;
|
|
152
153
|
var currentNeededSegment = segmentQueue[0];
|
|
153
|
-
|
|
154
|
+
/* eslint-disable-next-line @typescript-eslint/no-this-alias */
|
|
155
|
+
var self = this;
|
|
156
|
+
return observableDefer(function () {
|
|
157
|
+
return recursivelyRequestSegments(currentNeededSegment);
|
|
158
|
+
}).pipe(finalize(function () { _this._mediaSegmentRequest = null; }));
|
|
159
|
+
function recursivelyRequestSegments(startingSegment) {
|
|
154
160
|
if (startingSegment === undefined) {
|
|
155
161
|
return observableOf({ type: "end-of-queue",
|
|
156
162
|
value: null });
|
|
157
163
|
}
|
|
158
164
|
var segment = startingSegment.segment, priority = startingSegment.priority;
|
|
159
|
-
var context = objectAssign({ segment: segment },
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
165
|
+
var context = objectAssign({ segment: segment }, self._content);
|
|
166
|
+
return new Observable(function (obs) {
|
|
167
|
+
/** TaskCanceller linked to this Observable's lifecycle. */
|
|
168
|
+
var canceller = new TaskCanceller();
|
|
169
|
+
/**
|
|
170
|
+
* If `true` , the Observable has either errored, completed, or was
|
|
171
|
+
* unsubscribed from.
|
|
172
|
+
* This only conserves the Observable for the current segment's request,
|
|
173
|
+
* not the other recursively-created future ones.
|
|
174
|
+
*/
|
|
175
|
+
var isComplete = false;
|
|
176
|
+
/**
|
|
177
|
+
* Subscription to request the following segment (as this function is
|
|
178
|
+
* recursive).
|
|
179
|
+
* `undefined` if no following segment has been requested.
|
|
180
|
+
*/
|
|
181
|
+
var nextSegmentSubscription;
|
|
182
|
+
/**
|
|
183
|
+
* If true, we're currently waiting for the initialization segment to be
|
|
184
|
+
* parsed before parsing a received chunk.
|
|
185
|
+
*
|
|
186
|
+
* In that case, the `DownloadingQueue` has to remain careful to only
|
|
187
|
+
* send further events and complete the Observable only once the
|
|
188
|
+
* initialization segment has been parsed AND the chunk parsing has been
|
|
189
|
+
* done (this can be done very simply by listening to the same
|
|
190
|
+
* `ISharedReference`, as its callbacks are called in the same order
|
|
191
|
+
* than the one in which they are added.
|
|
192
|
+
*/
|
|
193
|
+
var isWaitingOnInitSegment = false;
|
|
194
|
+
/** Scheduled actual segment request. */
|
|
195
|
+
var request = self._segmentFetcher.createRequest(context, priority, {
|
|
196
|
+
/**
|
|
197
|
+
* Callback called when the request has to be retried.
|
|
198
|
+
* @param {Error} error
|
|
199
|
+
*/
|
|
200
|
+
onRetry: function (error) {
|
|
201
|
+
obs.next({ type: "retry", value: { segment: segment, error: error } });
|
|
202
|
+
},
|
|
203
|
+
/**
|
|
204
|
+
* Callback called when the request has to be interrupted and
|
|
205
|
+
* restarted later.
|
|
206
|
+
*/
|
|
207
|
+
beforeInterrupted: function () {
|
|
169
208
|
log.info("Stream: segment request interrupted temporarly.", segment.id, segment.time);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
209
|
+
},
|
|
210
|
+
/**
|
|
211
|
+
* Callback called when a decodable chunk of the segment is available.
|
|
212
|
+
* @param {Function} parse - Function allowing to parse the segment.
|
|
213
|
+
*/
|
|
214
|
+
onChunk: function (parse) {
|
|
215
|
+
var initTimescale = self._initSegmentInfoRef.getValue();
|
|
216
|
+
if (initTimescale !== undefined) {
|
|
217
|
+
emitChunk(parse(initTimescale !== null && initTimescale !== void 0 ? initTimescale : undefined));
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
isWaitingOnInitSegment = true;
|
|
221
|
+
// We could also technically call `waitUntilDefined` in both cases,
|
|
222
|
+
// but I found it globally clearer to segregate the two cases,
|
|
223
|
+
// especially to always have a meaningful `isWaitingOnInitSegment`
|
|
224
|
+
// boolean which is a very important variable.
|
|
225
|
+
self._initSegmentInfoRef.waitUntilDefined(function (actualTimescale) {
|
|
226
|
+
emitChunk(parse(actualTimescale !== null && actualTimescale !== void 0 ? actualTimescale : undefined));
|
|
227
|
+
}, { clearSignal: canceller.signal });
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
/** Callback called after all chunks have been sent. */
|
|
231
|
+
onAllChunksReceived: function () {
|
|
232
|
+
if (!isWaitingOnInitSegment) {
|
|
233
|
+
obs.next({ type: "end-of-segment",
|
|
234
|
+
value: { segment: segment } });
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
self._mediaSegmentsAwaitingInitMetadata.add(segment.id);
|
|
238
|
+
self._initSegmentInfoRef.waitUntilDefined(function () {
|
|
239
|
+
obs.next({ type: "end-of-segment",
|
|
240
|
+
value: { segment: segment } });
|
|
241
|
+
self._mediaSegmentsAwaitingInitMetadata.delete(segment.id);
|
|
242
|
+
isWaitingOnInitSegment = false;
|
|
243
|
+
}, { clearSignal: canceller.signal });
|
|
177
244
|
}
|
|
178
|
-
|
|
179
|
-
|
|
245
|
+
},
|
|
246
|
+
/**
|
|
247
|
+
* Callback called right after the request ended but before the next
|
|
248
|
+
* requests are scheduled. It is used to schedule the next segment.
|
|
249
|
+
*/
|
|
250
|
+
beforeEnded: function () {
|
|
251
|
+
self._mediaSegmentRequest = null;
|
|
252
|
+
if (isWaitingOnInitSegment) {
|
|
253
|
+
self._initSegmentInfoRef.waitUntilDefined(continueToNextSegment, { clearSignal: canceller.signal });
|
|
180
254
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
255
|
+
else {
|
|
256
|
+
continueToNextSegment();
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
}, canceller.signal);
|
|
260
|
+
request.catch(function (error) {
|
|
261
|
+
if (!isComplete) {
|
|
262
|
+
isComplete = true;
|
|
263
|
+
obs.error(error);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
self._mediaSegmentRequest = { segment: segment, priority: priority, request: request };
|
|
267
|
+
return function () {
|
|
268
|
+
self._mediaSegmentsAwaitingInitMetadata.delete(segment.id);
|
|
269
|
+
if (nextSegmentSubscription !== undefined) {
|
|
270
|
+
nextSegmentSubscription.unsubscribe();
|
|
271
|
+
}
|
|
272
|
+
if (isComplete) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
isComplete = true;
|
|
276
|
+
isWaitingOnInitSegment = false;
|
|
277
|
+
canceller.cancel();
|
|
278
|
+
};
|
|
279
|
+
function emitChunk(parsed) {
|
|
280
|
+
assert(parsed.segmentType === "media", "Should have loaded a media segment.");
|
|
281
|
+
obs.next(objectAssign({}, parsed, { type: "parsed-media", segment: segment }));
|
|
198
282
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
283
|
+
function continueToNextSegment() {
|
|
284
|
+
var lastQueue = self._downloadQueue.getValue().segmentQueue;
|
|
285
|
+
if (lastQueue.length === 0) {
|
|
286
|
+
obs.next({ type: "end-of-queue",
|
|
287
|
+
value: null });
|
|
288
|
+
isComplete = true;
|
|
289
|
+
obs.complete();
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
else if (lastQueue[0].segment.id === segment.id) {
|
|
293
|
+
lastQueue.shift();
|
|
294
|
+
}
|
|
295
|
+
isComplete = true;
|
|
296
|
+
nextSegmentSubscription = recursivelyRequestSegments(lastQueue[0])
|
|
297
|
+
.subscribe(obs);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}
|
|
204
301
|
};
|
|
205
302
|
/**
|
|
206
303
|
* Internal logic performing initialization segment requests.
|
|
@@ -213,41 +310,61 @@ var DownloadingQueue = /** @class */ (function () {
|
|
|
213
310
|
this._initSegmentRequest = null;
|
|
214
311
|
return EMPTY;
|
|
215
312
|
}
|
|
216
|
-
|
|
217
|
-
var
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
313
|
+
/* eslint-disable-next-line @typescript-eslint/no-this-alias */
|
|
314
|
+
var self = this;
|
|
315
|
+
return new Observable(function (obs) {
|
|
316
|
+
/** TaskCanceller linked to this Observable's lifecycle. */
|
|
317
|
+
var canceller = new TaskCanceller();
|
|
318
|
+
var segment = queuedInitSegment.segment, priority = queuedInitSegment.priority;
|
|
319
|
+
var context = objectAssign({ segment: segment }, _this._content);
|
|
320
|
+
/**
|
|
321
|
+
* If `true` , the Observable has either errored, completed, or was
|
|
322
|
+
* unsubscribed from.
|
|
323
|
+
*/
|
|
324
|
+
var isComplete = false;
|
|
325
|
+
var request = _this._segmentFetcher.createRequest(context, priority, {
|
|
326
|
+
onRetry: function (err) {
|
|
327
|
+
obs.next({ type: "retry",
|
|
328
|
+
value: { segment: segment, error: err } });
|
|
329
|
+
},
|
|
330
|
+
beforeInterrupted: function () {
|
|
227
331
|
log.info("Stream: init segment request interrupted temporarly.", segment.id);
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
|
|
332
|
+
},
|
|
333
|
+
beforeEnded: function () {
|
|
334
|
+
self._initSegmentRequest = null;
|
|
335
|
+
isComplete = true;
|
|
336
|
+
obs.complete();
|
|
337
|
+
},
|
|
338
|
+
onChunk: function (parse) {
|
|
339
|
+
var _a;
|
|
340
|
+
var parsed = parse(undefined);
|
|
341
|
+
assert(parsed.segmentType === "init", "Should have loaded an init segment.");
|
|
342
|
+
obs.next(objectAssign({}, parsed, { type: "parsed-init", segment: segment }));
|
|
343
|
+
if (parsed.segmentType === "init") {
|
|
344
|
+
self._initSegmentInfoRef.setValue((_a = parsed.initTimescale) !== null && _a !== void 0 ? _a : null);
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
onAllChunksReceived: function () {
|
|
348
|
+
obs.next({ type: "end-of-segment",
|
|
244
349
|
value: { segment: segment } });
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
350
|
+
},
|
|
351
|
+
}, canceller.signal);
|
|
352
|
+
request.catch(function (error) {
|
|
353
|
+
if (!isComplete) {
|
|
354
|
+
isComplete = true;
|
|
355
|
+
obs.error(error);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
_this._initSegmentRequest = { segment: segment, priority: priority, request: request };
|
|
359
|
+
return function () {
|
|
360
|
+
_this._initSegmentRequest = null;
|
|
361
|
+
if (isComplete) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
isComplete = true;
|
|
365
|
+
canceller.cancel();
|
|
366
|
+
};
|
|
367
|
+
});
|
|
251
368
|
};
|
|
252
369
|
return DownloadingQueue;
|
|
253
370
|
}());
|
|
@@ -390,7 +390,9 @@ export interface ILockedStreamEvent {
|
|
|
390
390
|
* decipherability status of some `Representation`(s).
|
|
391
391
|
*
|
|
392
392
|
* When that event is emitted, the current HTMLMediaElement's buffer might need
|
|
393
|
-
* to be "flushed" to continue (e.g. through a little seek operation)
|
|
393
|
+
* to be "flushed" to continue (e.g. through a little seek operation) or in
|
|
394
|
+
* worst cases completely removed and re-created through the "reload" mechanism,
|
|
395
|
+
* depending on the platform.
|
|
394
396
|
*/
|
|
395
397
|
export interface INeedsDecipherabilityFlush {
|
|
396
398
|
type: "needs-decipherability-flush";
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
import { IEncryptedMediaErrorKeyStatusObject } from "../public_types";
|
|
16
17
|
import { IEncryptedMediaErrorCode } from "./error_codes";
|
|
17
18
|
/**
|
|
18
19
|
* Error linked to the encryption of the media.
|
|
@@ -24,11 +25,15 @@ export default class EncryptedMediaError extends Error {
|
|
|
24
25
|
readonly name: "EncryptedMediaError";
|
|
25
26
|
readonly type: "ENCRYPTED_MEDIA_ERROR";
|
|
26
27
|
readonly code: IEncryptedMediaErrorCode;
|
|
28
|
+
readonly keyStatuses?: IEncryptedMediaErrorKeyStatusObject[];
|
|
27
29
|
message: string;
|
|
28
30
|
fatal: boolean;
|
|
29
31
|
/**
|
|
30
32
|
* @param {string} code
|
|
31
33
|
* @param {string} reason
|
|
32
34
|
*/
|
|
33
|
-
constructor(code:
|
|
35
|
+
constructor(code: "KEY_STATUS_CHANGE_ERROR", reason: string, supplementaryInfos: {
|
|
36
|
+
keyStatuses: IEncryptedMediaErrorKeyStatusObject[];
|
|
37
|
+
});
|
|
38
|
+
constructor(code: Omit<IEncryptedMediaErrorCode, "KEY_STATUS_CHANGE_ERROR">, reason: string);
|
|
34
39
|
}
|
|
@@ -38,11 +38,7 @@ import errorMessage from "./error_message";
|
|
|
38
38
|
*/
|
|
39
39
|
var EncryptedMediaError = /** @class */ (function (_super) {
|
|
40
40
|
__extends(EncryptedMediaError, _super);
|
|
41
|
-
|
|
42
|
-
* @param {string} code
|
|
43
|
-
* @param {string} reason
|
|
44
|
-
*/
|
|
45
|
-
function EncryptedMediaError(code, reason) {
|
|
41
|
+
function EncryptedMediaError(code, reason, supplementaryInfos) {
|
|
46
42
|
var _this = _super.call(this) || this;
|
|
47
43
|
// @see https://stackoverflow.com/questions/41102060/typescript-extending-error-class
|
|
48
44
|
Object.setPrototypeOf(_this, EncryptedMediaError.prototype);
|
|
@@ -51,6 +47,9 @@ var EncryptedMediaError = /** @class */ (function (_super) {
|
|
|
51
47
|
_this.code = code;
|
|
52
48
|
_this.message = errorMessage(_this.name, _this.code, reason);
|
|
53
49
|
_this.fatal = false;
|
|
50
|
+
if (typeof (supplementaryInfos === null || supplementaryInfos === void 0 ? void 0 : supplementaryInfos.keyStatuses) === "string") {
|
|
51
|
+
_this.keyStatuses = supplementaryInfos.keyStatuses;
|
|
52
|
+
}
|
|
54
53
|
return _this;
|
|
55
54
|
}
|
|
56
55
|
return EncryptedMediaError;
|
|
@@ -13,6 +13,6 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import VideoThumbnailLoader, { DASH_LOADER, MPL_LOADER } from "./
|
|
16
|
+
import VideoThumbnailLoader, { DASH_LOADER, MPL_LOADER } from "./video_thumbnail_loader";
|
|
17
17
|
export { DASH_LOADER, MPL_LOADER, };
|
|
18
18
|
export default VideoThumbnailLoader;
|
|
@@ -13,6 +13,6 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import VideoThumbnailLoader, { DASH_LOADER, MPL_LOADER, } from "./
|
|
16
|
+
import VideoThumbnailLoader, { DASH_LOADER, MPL_LOADER, } from "./video_thumbnail_loader";
|
|
17
17
|
export { DASH_LOADER, MPL_LOADER, };
|
|
18
18
|
export default VideoThumbnailLoader;
|
package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2015 CANAL+ Group
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { ISegmentFetcher, ISegmentLoaderContent } from "../../../core/fetchers/segment/segment_fetcher";
|
|
17
|
+
import { AudioVideoSegmentBuffer } from "../../../core/segment_buffers/implementations";
|
|
18
|
+
import { CancellationSignal } from "../../../utils/task_canceller";
|
|
19
|
+
/**
|
|
20
|
+
* @param {Object} segmentInfo
|
|
21
|
+
* @param {Object} segmentBuffer
|
|
22
|
+
* @param {Object} segmentFetcher
|
|
23
|
+
* @param {Object} cancelSignal
|
|
24
|
+
* @returns {Promise}
|
|
25
|
+
*/
|
|
26
|
+
export default function loadAndPushSegment(segmentInfo: ISegmentLoaderContent, segmentBuffer: AudioVideoSegmentBuffer, segmentFetcher: ISegmentFetcher<ArrayBuffer | Uint8Array>, cancelSignal: CancellationSignal): Promise<unknown>;
|