rx-player 4.0.0-beta.1 → 4.0.0-beta.2
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 +40 -0
- package/CONTRIBUTING.md +48 -168
- package/FILES.md +40 -92
- package/VERSION +1 -1
- package/dist/_esm5.processed/compat/browser_detection.d.ts +3 -1
- package/dist/_esm5.processed/compat/browser_detection.js +7 -2
- package/dist/_esm5.processed/compat/eme/load_session.js +1 -1
- package/dist/_esm5.processed/compat/has_issues_with_high_media_source_duration.d.ts +21 -0
- package/dist/_esm5.processed/compat/has_issues_with_high_media_source_duration.js +26 -0
- package/dist/_esm5.processed/config.d.ts +2 -0
- package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +5 -4
- package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.d.ts +18 -1
- package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.js +106 -25
- package/dist/_esm5.processed/core/adaptive/guess_based_chooser.js +6 -6
- package/dist/_esm5.processed/core/adaptive/network_analyzer.js +8 -5
- package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.d.ts +19 -1
- package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.js +1 -1
- package/dist/_esm5.processed/core/api/debug/render.js +1 -1
- package/dist/_esm5.processed/core/api/playback_observer.js +1 -0
- package/dist/_esm5.processed/core/api/public_api.d.ts +54 -1
- package/dist/_esm5.processed/core/api/public_api.js +232 -35
- package/dist/_esm5.processed/core/api/track_management/media_element_tracks_store.js +10 -1
- package/dist/_esm5.processed/core/api/track_management/track_dispatcher.d.ts +13 -1
- package/dist/_esm5.processed/core/api/track_management/track_dispatcher.js +30 -15
- package/dist/_esm5.processed/core/api/track_management/tracks_store.d.ts +3 -1
- package/dist/_esm5.processed/core/api/track_management/tracks_store.js +67 -152
- package/dist/_esm5.processed/core/api/utils.d.ts +10 -0
- package/dist/_esm5.processed/core/api/utils.js +20 -0
- package/dist/_esm5.processed/core/decrypt/session_events_listener.js +7 -1
- package/dist/_esm5.processed/core/decrypt/utils/clean_old_loaded_sessions.js +2 -0
- package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.js +5 -1
- package/dist/_esm5.processed/core/init/directfile_content_initializer.js +1 -1
- package/dist/_esm5.processed/core/init/media_source_content_initializer.js +47 -10
- package/dist/_esm5.processed/core/init/types.d.ts +9 -1
- package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.d.ts +28 -1
- package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.js +22 -9
- package/dist/_esm5.processed/core/init/utils/media_source_duration_updater.d.ts +58 -0
- package/dist/_esm5.processed/core/init/utils/{media_duration_updater.js → media_source_duration_updater.js} +84 -87
- package/dist/_esm5.processed/core/init/utils/rebuffering_controller.d.ts +36 -2
- package/dist/_esm5.processed/core/init/utils/rebuffering_controller.js +82 -2
- package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.d.ts +18 -7
- package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +31 -40
- package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.d.ts +8 -0
- package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +12 -0
- package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.d.ts +8 -0
- package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.js +12 -0
- package/dist/_esm5.processed/core/segment_buffers/implementations/types.d.ts +11 -4
- package/dist/_esm5.processed/core/segment_buffers/index.d.ts +2 -2
- package/dist/_esm5.processed/core/stream/adaptation/utils/create_representation_estimator.d.ts +47 -0
- package/dist/_esm5.processed/core/stream/adaptation/utils/create_representation_estimator.js +70 -0
- package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +15 -8
- package/dist/_esm5.processed/core/stream/period/period_stream.js +1 -1
- package/dist/_esm5.processed/core/stream/representation/representation_stream.js +22 -13
- package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.d.ts +4 -2
- package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.js +2 -2
- package/dist/_esm5.processed/core/stream/representation/utils/push_init_segment.d.ts +3 -2
- package/dist/_esm5.processed/core/stream/representation/utils/push_init_segment.js +8 -8
- package/dist/_esm5.processed/core/stream/representation/utils/push_media_segment.d.ts +2 -2
- package/dist/_esm5.processed/core/stream/representation/utils/push_media_segment.js +2 -3
- package/dist/_esm5.processed/default_config.d.ts +25 -0
- package/dist/_esm5.processed/default_config.js +27 -2
- package/dist/_esm5.processed/errors/index.d.ts +2 -2
- package/dist/_esm5.processed/errors/media_error.d.ts +23 -1
- package/dist/_esm5.processed/errors/media_error.js +18 -5
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.d.ts +1 -1
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.js +8 -7
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.js +17 -9
- package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/index.js +0 -2
- package/dist/_esm5.processed/manifest/adaptation.d.ts +21 -2
- package/dist/_esm5.processed/manifest/adaptation.js +76 -1
- package/dist/_esm5.processed/manifest/manifest.js +1 -1
- package/dist/_esm5.processed/manifest/period.js +2 -2
- package/dist/_esm5.processed/manifest/representation.d.ts +33 -2
- package/dist/_esm5.processed/manifest/representation.js +21 -0
- package/dist/_esm5.processed/manifest/utils.js +1 -3
- package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.d.ts +1 -1
- package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.js +1 -1
- package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.js +1 -0
- package/dist/_esm5.processed/public_types.d.ts +13 -3
- package/dist/_esm5.processed/tools/TextTrackRenderer/text_track_renderer.js +1 -1
- package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.d.ts +4 -6
- package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.js +4 -6
- package/dist/_esm5.processed/utils/is_null_or_undefined.d.ts +1 -1
- package/dist/_esm5.processed/utils/is_null_or_undefined.js +1 -1
- package/dist/mpd-parser.wasm +0 -0
- package/dist/rx-player.js +4709 -4218
- package/dist/rx-player.min.js +1 -1
- package/package.json +42 -36
- package/scripts/build/generate_build.js +1 -1
- package/scripts/fast_demo_build.js +4 -3
- package/scripts/generate_full_demo.js +1 -1
- package/sonar-project.properties +1 -1
- package/src/compat/browser_detection.ts +7 -1
- package/src/compat/eme/load_session.ts +1 -1
- package/src/compat/has_issues_with_high_media_source_duration.ts +27 -0
- package/src/core/adaptive/__tests__/buffer_based_chooser.test.ts +147 -48
- package/src/core/adaptive/adaptive_representation_selector.ts +7 -4
- package/src/core/adaptive/buffer_based_chooser.ts +144 -26
- package/src/core/adaptive/guess_based_chooser.ts +9 -8
- package/src/core/adaptive/network_analyzer.ts +9 -4
- package/src/core/adaptive/utils/representation_score_calculator.ts +22 -2
- package/src/core/api/debug/render.ts +1 -1
- package/src/core/api/playback_observer.ts +1 -0
- package/src/core/api/public_api.ts +277 -44
- package/src/core/api/track_management/media_element_tracks_store.ts +17 -8
- package/src/core/api/track_management/track_dispatcher.ts +37 -14
- package/src/core/api/track_management/tracks_store.ts +77 -167
- package/src/core/api/utils.ts +26 -0
- package/src/core/decrypt/session_events_listener.ts +6 -1
- package/src/core/decrypt/utils/clean_old_loaded_sessions.ts +2 -1
- package/src/core/decrypt/utils/loaded_sessions_store.ts +8 -1
- package/src/core/init/directfile_content_initializer.ts +1 -0
- package/src/core/init/media_source_content_initializer.ts +52 -9
- package/src/core/init/types.ts +9 -1
- package/src/core/init/utils/content_time_boundaries_observer.ts +46 -10
- package/src/core/init/utils/{media_duration_updater.ts → media_source_duration_updater.ts} +100 -112
- package/src/core/init/utils/rebuffering_controller.ts +114 -3
- package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +56 -55
- package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +16 -0
- package/src/core/segment_buffers/implementations/text/native/native_text_segment_buffer.ts +16 -0
- package/src/core/segment_buffers/implementations/types.ts +16 -4
- package/src/core/segment_buffers/index.ts +2 -0
- package/src/core/stream/adaptation/utils/create_representation_estimator.ts +114 -0
- package/src/core/stream/orchestrator/stream_orchestrator.ts +16 -8
- package/src/core/stream/period/period_stream.ts +2 -1
- package/src/core/stream/representation/representation_stream.ts +34 -22
- package/src/core/stream/representation/utils/append_segment_to_buffer.ts +8 -3
- package/src/core/stream/representation/utils/push_init_segment.ts +11 -6
- package/src/core/stream/representation/utils/push_media_segment.ts +3 -3
- package/src/default_config.ts +29 -2
- package/src/errors/__tests__/media_error.test.ts +6 -6
- package/src/errors/index.ts +4 -1
- package/src/errors/media_error.ts +67 -1
- package/src/experimental/tools/VideoThumbnailLoader/load_and_push_segment.ts +10 -7
- package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +17 -6
- package/src/experimental/tools/mediaCapabilitiesProber/index.ts +0 -4
- package/src/manifest/__tests__/manifest.test.ts +7 -7
- package/src/manifest/__tests__/period.test.ts +90 -45
- package/src/manifest/adaptation.ts +89 -1
- package/src/manifest/manifest.ts +1 -1
- package/src/manifest/period.ts +4 -2
- package/src/manifest/representation.ts +67 -1
- package/src/manifest/utils.ts +1 -3
- package/src/parsers/manifest/dash/js-parser/parse_from_document.ts +1 -1
- package/src/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.ts +1 -0
- package/src/parsers/texttracks/ttml/parse_ttml.ts +1 -1
- package/src/public_types.ts +16 -1
- package/src/tools/TextTrackRenderer/text_track_renderer.ts +1 -1
- package/src/transports/smooth/isobmff/create_boxes.ts +4 -6
- package/src/typings/globals.d.ts +20 -20
- package/src/utils/is_null_or_undefined.ts +1 -1
- package/dist/_esm5.processed/core/init/utils/media_duration_updater.d.ts +0 -56
- package/scripts/doc-generator/construct_table_of_contents.js +0 -76
- package/scripts/doc-generator/convert_MD_to_HMTL.js +0 -26
- package/scripts/doc-generator/create_documentation.js +0 -331
- package/scripts/doc-generator/create_documentation_page.js +0 -209
- package/scripts/doc-generator/create_page.js +0 -210
- package/scripts/doc-generator/generate_header_html.js +0 -147
- package/scripts/doc-generator/generate_page_html.js +0 -115
- package/scripts/doc-generator/generate_page_list_html.js +0 -92
- package/scripts/doc-generator/generate_sidebar_html.js +0 -85
- package/scripts/doc-generator/get_search_data_for_content.js +0 -137
- package/scripts/doc-generator/index.js +0 -34
- package/scripts/doc-generator/parse_doc_configs.js +0 -327
- package/scripts/doc-generator/scripts/lunr.js +0 -10
- package/scripts/doc-generator/scripts/script.js +0 -451
- package/scripts/doc-generator/styles/code.css +0 -99
- package/scripts/doc-generator/styles/style.css +0 -835
- package/scripts/doc-generator/utils.js +0 -74
|
@@ -87,7 +87,7 @@ import getInitialTime from "./utils/get_initial_time";
|
|
|
87
87
|
import getLoadedReference from "./utils/get_loaded_reference";
|
|
88
88
|
import performInitialSeekAndPlay from "./utils/initial_seek_and_play";
|
|
89
89
|
import initializeContentDecryption from "./utils/initialize_content_decryption";
|
|
90
|
-
import
|
|
90
|
+
import MediaSourceDurationUpdater from "./utils/media_source_duration_updater";
|
|
91
91
|
import RebufferingController from "./utils/rebuffering_controller";
|
|
92
92
|
import streamEventsEmitter from "./utils/stream_events_emitter";
|
|
93
93
|
import listenToMediaError from "./utils/throw_on_media_error";
|
|
@@ -249,7 +249,7 @@ var MediaSourceContentInitializer = /** @class */ (function (_super) {
|
|
|
249
249
|
if (initCanceller.isUsed()) {
|
|
250
250
|
return;
|
|
251
251
|
}
|
|
252
|
-
triggerEvent("reloadingMediaSource",
|
|
252
|
+
triggerEvent("reloadingMediaSource", reloadOrder);
|
|
253
253
|
if (initCanceller.isUsed()) {
|
|
254
254
|
return;
|
|
255
255
|
}
|
|
@@ -341,7 +341,18 @@ var MediaSourceContentInitializer = /** @class */ (function (_super) {
|
|
|
341
341
|
}
|
|
342
342
|
}, { clearSignal: cancelSignal, emitCurrentValue: true });
|
|
343
343
|
var streamObserver = createStreamPlaybackObserver(manifest, playbackObserver, { autoPlay: autoPlay, initialPlayPerformed: initialPlayPerformed, initialSeekPerformed: initialSeekPerformed, speed: speed, startTime: initialTime });
|
|
344
|
-
var rebufferingController = this._createRebufferingController(playbackObserver, manifest, speed, cancelSignal);
|
|
344
|
+
var rebufferingController = this._createRebufferingController(playbackObserver, manifest, segmentBuffersStore, speed, cancelSignal);
|
|
345
|
+
rebufferingController.addEventListener("needsReload", function () {
|
|
346
|
+
// NOTE couldn't both be always calculated at event destination?
|
|
347
|
+
// Maybe there are exceptions?
|
|
348
|
+
var position = initialSeekPerformed.getValue() ?
|
|
349
|
+
playbackObserver.getCurrentTime() :
|
|
350
|
+
initialTime;
|
|
351
|
+
var autoplay = initialPlayPerformed.getValue() ?
|
|
352
|
+
!playbackObserver.getIsPaused() :
|
|
353
|
+
autoPlay;
|
|
354
|
+
onReloadOrder({ position: position, autoPlay: autoplay });
|
|
355
|
+
}, cancelSignal);
|
|
345
356
|
var contentTimeBoundariesObserver = this
|
|
346
357
|
._createContentTimeBoundariesObserver(manifest, mediaSource, streamObserver, segmentBuffersStore, cancelSignal);
|
|
347
358
|
/**
|
|
@@ -376,7 +387,32 @@ var MediaSourceContentInitializer = /** @class */ (function (_super) {
|
|
|
376
387
|
function handleStreamOrchestratorCallbacks() {
|
|
377
388
|
return {
|
|
378
389
|
needsBufferFlush: function () {
|
|
379
|
-
|
|
390
|
+
var seekedTime = mediaElement.currentTime + 0.001;
|
|
391
|
+
playbackObserver.setCurrentTime(seekedTime);
|
|
392
|
+
// Seek again once data begins to be buffered.
|
|
393
|
+
// This is sadly necessary on some browsers to avoid decoding
|
|
394
|
+
// issues after a flush.
|
|
395
|
+
//
|
|
396
|
+
// NOTE: there's in theory a potential race condition in the following
|
|
397
|
+
// logic as the callback could be called when media data is still
|
|
398
|
+
// being removed by the browser - which is an asynchronous process.
|
|
399
|
+
// The following condition checking for buffered data could thus lead
|
|
400
|
+
// to a false positive where we're actually checking previous data.
|
|
401
|
+
// For now, such scenario is avoided by setting the
|
|
402
|
+
// `includeLastObservation` option to `false` and calling
|
|
403
|
+
// `needsBufferFlush` once MSE media removal operations have been
|
|
404
|
+
// explicitely validated by the browser, but that's a complex and easy
|
|
405
|
+
// to break system.
|
|
406
|
+
playbackObserver.listen(function (obs, stopListening) {
|
|
407
|
+
if (
|
|
408
|
+
// Data is buffered around the current position
|
|
409
|
+
obs.currentRange !== null ||
|
|
410
|
+
// Or, for whatever reason, playback is already advancing
|
|
411
|
+
obs.position > seekedTime + 0.1) {
|
|
412
|
+
stopListening();
|
|
413
|
+
playbackObserver.setCurrentTime(obs.position + 0.001);
|
|
414
|
+
}
|
|
415
|
+
}, { includeLastObservation: false, clearSignal: cancelSignal });
|
|
380
416
|
},
|
|
381
417
|
streamStatusUpdate: function (value) {
|
|
382
418
|
// Announce discontinuities if found
|
|
@@ -498,9 +534,9 @@ var MediaSourceContentInitializer = /** @class */ (function (_super) {
|
|
|
498
534
|
MediaSourceContentInitializer.prototype._createContentTimeBoundariesObserver = function (manifest, mediaSource, streamObserver, segmentBuffersStore, cancelSignal) {
|
|
499
535
|
var _this = this;
|
|
500
536
|
/** Maintains the MediaSource's duration up-to-date with the Manifest */
|
|
501
|
-
var
|
|
537
|
+
var mediaSourceDurationUpdater = new MediaSourceDurationUpdater(mediaSource);
|
|
502
538
|
cancelSignal.register(function () {
|
|
503
|
-
|
|
539
|
+
mediaSourceDurationUpdater.stopUpdating();
|
|
504
540
|
});
|
|
505
541
|
/** Allows to cancel a pending `end-of-stream` operation. */
|
|
506
542
|
var endOfStreamCanceller = null;
|
|
@@ -515,8 +551,7 @@ var MediaSourceContentInitializer = /** @class */ (function (_super) {
|
|
|
515
551
|
_this.trigger("activePeriodChanged", { period: period });
|
|
516
552
|
});
|
|
517
553
|
contentTimeBoundariesObserver.addEventListener("durationUpdate", function (newDuration) {
|
|
518
|
-
|
|
519
|
-
mediaDurationUpdater.updateKnownDuration(newDuration);
|
|
554
|
+
mediaSourceDurationUpdater.updateDuration(newDuration.duration, newDuration.isEnd);
|
|
520
555
|
});
|
|
521
556
|
contentTimeBoundariesObserver.addEventListener("endOfStream", function () {
|
|
522
557
|
if (endOfStreamCanceller === null) {
|
|
@@ -533,6 +568,8 @@ var MediaSourceContentInitializer = /** @class */ (function (_super) {
|
|
|
533
568
|
endOfStreamCanceller = null;
|
|
534
569
|
}
|
|
535
570
|
});
|
|
571
|
+
var currentDuration = contentTimeBoundariesObserver.getCurrentDuration();
|
|
572
|
+
mediaSourceDurationUpdater.updateDuration(currentDuration.duration, currentDuration.isEnd);
|
|
536
573
|
return contentTimeBoundariesObserver;
|
|
537
574
|
};
|
|
538
575
|
/**
|
|
@@ -553,9 +590,9 @@ var MediaSourceContentInitializer = /** @class */ (function (_super) {
|
|
|
553
590
|
* @param {Object} cancelSignal
|
|
554
591
|
* @returns {Object}
|
|
555
592
|
*/
|
|
556
|
-
MediaSourceContentInitializer.prototype._createRebufferingController = function (playbackObserver, manifest, speed, cancelSignal) {
|
|
593
|
+
MediaSourceContentInitializer.prototype._createRebufferingController = function (playbackObserver, manifest, segmentBuffersStore, speed, cancelSignal) {
|
|
557
594
|
var _this = this;
|
|
558
|
-
var rebufferingController = new RebufferingController(playbackObserver, manifest, speed);
|
|
595
|
+
var rebufferingController = new RebufferingController(playbackObserver, manifest, segmentBuffersStore, speed);
|
|
559
596
|
// Bubble-up events
|
|
560
597
|
rebufferingController.addEventListener("stalled", function (evt) { return _this.trigger("stalled", evt); });
|
|
561
598
|
rebufferingController.addEventListener("unstalled", function () { return _this.trigger("unstalled", null); });
|
|
@@ -95,7 +95,15 @@ export interface IContentInitializerEvents {
|
|
|
95
95
|
* Event sent when we're starting attach a new MediaSource to the media element
|
|
96
96
|
* (after removing the previous one).
|
|
97
97
|
*/
|
|
98
|
-
reloadingMediaSource:
|
|
98
|
+
reloadingMediaSource: {
|
|
99
|
+
/** The position we're reloading at, in seconds. */
|
|
100
|
+
position: number;
|
|
101
|
+
/**
|
|
102
|
+
* If `true`, we'll play directly after finishing the reloading operation.
|
|
103
|
+
* If `false`, we'll be paused after it.
|
|
104
|
+
*/
|
|
105
|
+
autoPlay: boolean;
|
|
106
|
+
};
|
|
99
107
|
/** Event sent after the player stalled. */
|
|
100
108
|
stalled: IStallingSituation;
|
|
101
109
|
/** Event sent when the player goes out of a stalling situation. */
|
|
@@ -55,6 +55,11 @@ export default class ContentTimeBoundariesObserver extends EventEmitter<IContent
|
|
|
55
55
|
* @param {Object} playbackObserver
|
|
56
56
|
*/
|
|
57
57
|
constructor(manifest: Manifest, playbackObserver: IReadOnlyPlaybackObserver<IStreamOrchestratorPlaybackObservation>, bufferTypes: IBufferType[]);
|
|
58
|
+
/**
|
|
59
|
+
* Returns an estimate of the current duration of the content.
|
|
60
|
+
* @returns {Object}
|
|
61
|
+
*/
|
|
62
|
+
getCurrentDuration(): IDurationItem;
|
|
58
63
|
/**
|
|
59
64
|
* Method to call any time an Adaptation has been selected.
|
|
60
65
|
*
|
|
@@ -121,9 +126,31 @@ export default class ContentTimeBoundariesObserver extends EventEmitter<IContent
|
|
|
121
126
|
private _addActivelyLoadedPeriod;
|
|
122
127
|
private _removeActivelyLoadedPeriod;
|
|
123
128
|
private _checkCurrentPeriod;
|
|
129
|
+
private _getManifestDuration;
|
|
124
130
|
private _lazilyCreateActiveStreamInfo;
|
|
125
131
|
private _checkEndOfStream;
|
|
126
132
|
}
|
|
133
|
+
export interface IDurationItem {
|
|
134
|
+
/**
|
|
135
|
+
* The new maximum known position (note that this is the ending position
|
|
136
|
+
* currently known of the current content, it might be superior to the last
|
|
137
|
+
* position at which segments are available and it might also evolve over
|
|
138
|
+
* time), in seconds.
|
|
139
|
+
*/
|
|
140
|
+
duration: number;
|
|
141
|
+
/**
|
|
142
|
+
* If `true`, the communicated `duration` is the actual end of the content.
|
|
143
|
+
* It may still be updated due to a track change or to add precision, but it
|
|
144
|
+
* is still a (rough) estimate of the maximum position that content should
|
|
145
|
+
* have.
|
|
146
|
+
*
|
|
147
|
+
* If `false`, this is the currently known maximum position associated to
|
|
148
|
+
* the content, but the content is still evolving (typically, new media
|
|
149
|
+
* segments are still being generated) and as such it can still have a
|
|
150
|
+
* longer duration in the future.
|
|
151
|
+
*/
|
|
152
|
+
isEnd: boolean;
|
|
153
|
+
}
|
|
127
154
|
/**
|
|
128
155
|
* Events triggered by a `ContentTimeBoundariesObserver` where the keys are the
|
|
129
156
|
* event names and the value is the payload of those events.
|
|
@@ -137,7 +164,7 @@ export interface IContentTimeBoundariesObserverEvent {
|
|
|
137
164
|
* Triggered when the duration of the currently-playing content became known
|
|
138
165
|
* or changed.
|
|
139
166
|
*/
|
|
140
|
-
durationUpdate:
|
|
167
|
+
durationUpdate: IDurationItem;
|
|
141
168
|
/**
|
|
142
169
|
* Triggered when the last possible chronological segment for all types of
|
|
143
170
|
* buffers has either been pushed or is being pushed to the corresponding
|
|
@@ -82,19 +82,21 @@ var ContentTimeBoundariesObserver = /** @class */ (function (_super) {
|
|
|
82
82
|
}
|
|
83
83
|
}, { includeLastObservation: true, clearSignal: cancelSignal });
|
|
84
84
|
manifest.addEventListener("manifestUpdate", function () {
|
|
85
|
-
_this.trigger("durationUpdate",
|
|
85
|
+
_this.trigger("durationUpdate", _this._getManifestDuration());
|
|
86
86
|
if (cancelSignal.isCancelled()) {
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
89
|
_this._checkEndOfStream();
|
|
90
90
|
}, cancelSignal);
|
|
91
|
-
function getManifestDuration() {
|
|
92
|
-
return manifest.isDynamic ?
|
|
93
|
-
maximumPositionCalculator.getMaximumAvailablePosition() :
|
|
94
|
-
maximumPositionCalculator.getEndingPosition();
|
|
95
|
-
}
|
|
96
91
|
return _this;
|
|
97
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Returns an estimate of the current duration of the content.
|
|
95
|
+
* @returns {Object}
|
|
96
|
+
*/
|
|
97
|
+
ContentTimeBoundariesObserver.prototype.getCurrentDuration = function () {
|
|
98
|
+
return this._getManifestDuration();
|
|
99
|
+
};
|
|
98
100
|
/**
|
|
99
101
|
* Method to call any time an Adaptation has been selected.
|
|
100
102
|
*
|
|
@@ -121,9 +123,12 @@ var ContentTimeBoundariesObserver = /** @class */ (function (_super) {
|
|
|
121
123
|
this._maximumPositionCalculator
|
|
122
124
|
.updateLastVideoAdaptation(adaptation);
|
|
123
125
|
}
|
|
124
|
-
var
|
|
125
|
-
|
|
126
|
-
|
|
126
|
+
var endingPosition = this._maximumPositionCalculator.getEndingPosition();
|
|
127
|
+
var newDuration = endingPosition !== undefined ?
|
|
128
|
+
{ isEnd: true,
|
|
129
|
+
duration: endingPosition } :
|
|
130
|
+
{ isEnd: false,
|
|
131
|
+
duration: this._maximumPositionCalculator.getMaximumAvailablePosition() };
|
|
127
132
|
this.trigger("durationUpdate", newDuration);
|
|
128
133
|
}
|
|
129
134
|
}
|
|
@@ -258,6 +263,14 @@ var ContentTimeBoundariesObserver = /** @class */ (function (_super) {
|
|
|
258
263
|
return state_1.value;
|
|
259
264
|
}
|
|
260
265
|
};
|
|
266
|
+
ContentTimeBoundariesObserver.prototype._getManifestDuration = function () {
|
|
267
|
+
var endingPosition = this._maximumPositionCalculator.getEndingPosition();
|
|
268
|
+
return endingPosition !== undefined ?
|
|
269
|
+
{ isEnd: true,
|
|
270
|
+
duration: endingPosition } :
|
|
271
|
+
{ isEnd: false,
|
|
272
|
+
duration: this._maximumPositionCalculator.getMaximumAvailablePosition() };
|
|
273
|
+
};
|
|
261
274
|
ContentTimeBoundariesObserver.prototype._lazilyCreateActiveStreamInfo = function (bufferType) {
|
|
262
275
|
var streamInfo = this._activeStreams.get(bufferType);
|
|
263
276
|
if (streamInfo === undefined) {
|
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
/**
|
|
17
|
+
* Keep the MediaSource's `duration` attribute up-to-date with the duration of
|
|
18
|
+
* the content played on it.
|
|
19
|
+
* @class MediaSourceDurationUpdater
|
|
20
|
+
*/
|
|
21
|
+
export default class MediaSourceDurationUpdater {
|
|
22
|
+
/**
|
|
23
|
+
* `MediaSource` on which we're going to update the `duration` attribute.
|
|
24
|
+
*/
|
|
25
|
+
private _mediaSource;
|
|
26
|
+
/**
|
|
27
|
+
* Abort the current duration-setting logic.
|
|
28
|
+
* `null` if no such logic is pending.
|
|
29
|
+
*/
|
|
30
|
+
private _currentMediaSourceDurationUpdateCanceller;
|
|
31
|
+
/**
|
|
32
|
+
* Create a new `MediaSourceDurationUpdater`,
|
|
33
|
+
* @param {MediaSource} mediaSource - The MediaSource on which the content is
|
|
34
|
+
* played.
|
|
35
|
+
*/
|
|
36
|
+
constructor(mediaSource: MediaSource);
|
|
37
|
+
/**
|
|
38
|
+
* Indicate to the `MediaSourceDurationUpdater` the currently known duration
|
|
39
|
+
* of the content.
|
|
40
|
+
*
|
|
41
|
+
* The `MediaSourceDurationUpdater` will then use that value to determine
|
|
42
|
+
* which `duration` attribute should be set on the `MediaSource` associated
|
|
43
|
+
*
|
|
44
|
+
* @param {number} newDuration
|
|
45
|
+
* @param {boolean} isRealEndKnown - If set to `false`, the current content is
|
|
46
|
+
* a dynamic content (it might evolve in the future) and the `newDuration`
|
|
47
|
+
* communicated might be greater still. In effect the
|
|
48
|
+
* `MediaSourceDurationUpdater` will actually set a much higher value to the
|
|
49
|
+
* `MediaSource`'s duration to prevent being annoyed by the HTML-related
|
|
50
|
+
* side-effects of having a too low duration (such as the impossibility to
|
|
51
|
+
* seek over that value).
|
|
52
|
+
*/
|
|
53
|
+
updateDuration(newDuration: number, isRealEndKnown: boolean): void;
|
|
54
|
+
/**
|
|
55
|
+
* Abort the last duration-setting operation and free its resources.
|
|
56
|
+
*/
|
|
57
|
+
stopUpdating(): void;
|
|
58
|
+
}
|
|
@@ -14,96 +14,91 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import { onSourceOpen, onSourceEnded, onSourceClose, } from "../../../compat/event_listeners";
|
|
17
|
+
/* eslint-disable-next-line max-len */
|
|
18
|
+
import hasIssuesWithHighMediaSourceDuration from "../../../compat/has_issues_with_high_media_source_duration";
|
|
17
19
|
import log from "../../../log";
|
|
18
20
|
import createSharedReference from "../../../utils/reference";
|
|
19
21
|
import TaskCanceller from "../../../utils/task_canceller";
|
|
20
22
|
/** Number of seconds in a regular year. */
|
|
21
23
|
var YEAR_IN_SECONDS = 365 * 24 * 3600;
|
|
22
24
|
/**
|
|
23
|
-
* Keep the MediaSource's duration up-to-date with
|
|
24
|
-
*
|
|
25
|
+
* Keep the MediaSource's `duration` attribute up-to-date with the duration of
|
|
26
|
+
* the content played on it.
|
|
27
|
+
* @class MediaSourceDurationUpdater
|
|
25
28
|
*/
|
|
26
|
-
var
|
|
29
|
+
var MediaSourceDurationUpdater = /** @class */ (function () {
|
|
27
30
|
/**
|
|
28
|
-
* Create a new `
|
|
29
|
-
* duration as soon as possible.
|
|
30
|
-
* This duration will be updated until the `stop` method is called.
|
|
31
|
-
* @param {Object} manifest - The Manifest currently played.
|
|
32
|
-
* For another content, you will have to create another `MediaDurationUpdater`.
|
|
31
|
+
* Create a new `MediaSourceDurationUpdater`,
|
|
33
32
|
* @param {MediaSource} mediaSource - The MediaSource on which the content is
|
|
34
|
-
*
|
|
33
|
+
* played.
|
|
35
34
|
*/
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
function MediaSourceDurationUpdater(mediaSource) {
|
|
36
|
+
this._mediaSource = mediaSource;
|
|
37
|
+
this._currentMediaSourceDurationUpdateCanceller = null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Indicate to the `MediaSourceDurationUpdater` the currently known duration
|
|
41
|
+
* of the content.
|
|
42
|
+
*
|
|
43
|
+
* The `MediaSourceDurationUpdater` will then use that value to determine
|
|
44
|
+
* which `duration` attribute should be set on the `MediaSource` associated
|
|
45
|
+
*
|
|
46
|
+
* @param {number} newDuration
|
|
47
|
+
* @param {boolean} isRealEndKnown - If set to `false`, the current content is
|
|
48
|
+
* a dynamic content (it might evolve in the future) and the `newDuration`
|
|
49
|
+
* communicated might be greater still. In effect the
|
|
50
|
+
* `MediaSourceDurationUpdater` will actually set a much higher value to the
|
|
51
|
+
* `MediaSource`'s duration to prevent being annoyed by the HTML-related
|
|
52
|
+
* side-effects of having a too low duration (such as the impossibility to
|
|
53
|
+
* seek over that value).
|
|
54
|
+
*/
|
|
55
|
+
MediaSourceDurationUpdater.prototype.updateDuration = function (newDuration, isRealEndKnown) {
|
|
56
|
+
if (this._currentMediaSourceDurationUpdateCanceller !== null) {
|
|
57
|
+
this._currentMediaSourceDurationUpdateCanceller.cancel();
|
|
58
|
+
}
|
|
59
|
+
this._currentMediaSourceDurationUpdateCanceller = new TaskCanceller();
|
|
60
|
+
var mediaSource = this._mediaSource;
|
|
61
|
+
var currentSignal = this._currentMediaSourceDurationUpdateCanceller.signal;
|
|
62
|
+
var isMediaSourceOpened = createMediaSourceOpenReference(mediaSource, currentSignal);
|
|
63
|
+
/** TaskCanceller triggered each time the MediaSource switches to and from "open". */
|
|
64
|
+
var msOpenStatusCanceller = new TaskCanceller();
|
|
65
|
+
msOpenStatusCanceller.linkToSignal(currentSignal);
|
|
45
66
|
isMediaSourceOpened.onUpdate(onMediaSourceOpenedStatusChanged, { emitCurrentValue: true,
|
|
46
|
-
clearSignal:
|
|
67
|
+
clearSignal: currentSignal });
|
|
47
68
|
function onMediaSourceOpenedStatusChanged() {
|
|
48
|
-
|
|
69
|
+
msOpenStatusCanceller.cancel();
|
|
49
70
|
if (!isMediaSourceOpened.getValue()) {
|
|
50
71
|
return;
|
|
51
72
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
var durationChangeCanceller = new TaskCanceller();
|
|
56
|
-
durationChangeCanceller.linkToSignal(msUpdateCanceller.signal);
|
|
57
|
-
var reSetDuration = function () {
|
|
58
|
-
durationChangeCanceller.cancel();
|
|
59
|
-
durationChangeCanceller = new TaskCanceller();
|
|
60
|
-
durationChangeCanceller.linkToSignal(msUpdateCanceller.signal);
|
|
61
|
-
onDurationMayHaveChanged(durationChangeCanceller.signal);
|
|
62
|
-
};
|
|
63
|
-
currentKnownDuration.onUpdate(reSetDuration, { emitCurrentValue: false,
|
|
64
|
-
clearSignal: msUpdateCanceller.signal });
|
|
65
|
-
manifest.addEventListener("manifestUpdate", reSetDuration, msUpdateCanceller.signal);
|
|
66
|
-
onDurationMayHaveChanged(durationChangeCanceller.signal);
|
|
67
|
-
}
|
|
68
|
-
function onDurationMayHaveChanged(cancelSignal) {
|
|
69
|
-
var areSourceBuffersUpdating = createSourceBuffersUpdatingReference(mediaSource.sourceBuffers, cancelSignal);
|
|
73
|
+
msOpenStatusCanceller = new TaskCanceller();
|
|
74
|
+
msOpenStatusCanceller.linkToSignal(currentSignal);
|
|
75
|
+
var areSourceBuffersUpdating = createSourceBuffersUpdatingReference(mediaSource.sourceBuffers, msOpenStatusCanceller.signal);
|
|
70
76
|
/** TaskCanceller triggered each time SourceBuffers' updating status changes */
|
|
71
77
|
var sourceBuffersUpdatingCanceller = new TaskCanceller();
|
|
72
|
-
sourceBuffersUpdatingCanceller.linkToSignal(
|
|
78
|
+
sourceBuffersUpdatingCanceller.linkToSignal(msOpenStatusCanceller.signal);
|
|
73
79
|
return areSourceBuffersUpdating.onUpdate(function (areUpdating) {
|
|
74
80
|
sourceBuffersUpdatingCanceller.cancel();
|
|
75
81
|
sourceBuffersUpdatingCanceller = new TaskCanceller();
|
|
76
|
-
sourceBuffersUpdatingCanceller.linkToSignal(
|
|
82
|
+
sourceBuffersUpdatingCanceller.linkToSignal(msOpenStatusCanceller.signal);
|
|
77
83
|
if (areUpdating) {
|
|
78
84
|
return;
|
|
79
85
|
}
|
|
80
|
-
recursivelyForceDurationUpdate(mediaSource,
|
|
81
|
-
}, { clearSignal:
|
|
86
|
+
recursivelyForceDurationUpdate(mediaSource, newDuration, isRealEndKnown, sourceBuffersUpdatingCanceller.signal);
|
|
87
|
+
}, { clearSignal: msOpenStatusCanceller.signal, emitCurrentValue: true });
|
|
82
88
|
}
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* By default, the `MediaDurationUpdater` only set a safe estimate for the
|
|
86
|
-
* MediaSource's duration.
|
|
87
|
-
* A more precize duration can be set by communicating to it a more precize
|
|
88
|
-
* media duration through `updateKnownDuration`.
|
|
89
|
-
* If the duration becomes unknown, `undefined` can be given to it so the
|
|
90
|
-
* `MediaDurationUpdater` goes back to a safe estimate.
|
|
91
|
-
* @param {number | undefined} newDuration
|
|
92
|
-
*/
|
|
93
|
-
MediaDurationUpdater.prototype.updateKnownDuration = function (newDuration) {
|
|
94
|
-
this._currentKnownDuration.setValueIfChanged(newDuration);
|
|
95
89
|
};
|
|
96
90
|
/**
|
|
97
|
-
*
|
|
98
|
-
* Once stopped, it is not possible to start it again, beside creating another
|
|
99
|
-
* `MediaDurationUpdater`.
|
|
91
|
+
* Abort the last duration-setting operation and free its resources.
|
|
100
92
|
*/
|
|
101
|
-
|
|
102
|
-
this.
|
|
93
|
+
MediaSourceDurationUpdater.prototype.stopUpdating = function () {
|
|
94
|
+
if (this._currentMediaSourceDurationUpdateCanceller !== null) {
|
|
95
|
+
this._currentMediaSourceDurationUpdateCanceller.cancel();
|
|
96
|
+
this._currentMediaSourceDurationUpdateCanceller = null;
|
|
97
|
+
}
|
|
103
98
|
};
|
|
104
|
-
return
|
|
99
|
+
return MediaSourceDurationUpdater;
|
|
105
100
|
}());
|
|
106
|
-
export default
|
|
101
|
+
export default MediaSourceDurationUpdater;
|
|
107
102
|
/**
|
|
108
103
|
* Checks that duration can be updated on the MediaSource, and then
|
|
109
104
|
* sets it.
|
|
@@ -113,28 +108,16 @@ export default MediaDurationUpdater;
|
|
|
113
108
|
* - `null` if it hasn'nt been updated
|
|
114
109
|
*
|
|
115
110
|
* @param {MediaSource} mediaSource
|
|
116
|
-
* @param {
|
|
111
|
+
* @param {number} duration
|
|
112
|
+
* @param {boolean} isRealEndKnown
|
|
117
113
|
* @returns {string}
|
|
118
114
|
*/
|
|
119
|
-
function setMediaSourceDuration(mediaSource,
|
|
120
|
-
var
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
newDuration = manifest.getMaximumSafePosition();
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
if (manifest.isDynamic) {
|
|
131
|
-
// Some targets poorly support setting a very high number for durations.
|
|
132
|
-
// Yet, in dynamic contents, we would prefer setting a value as high as possible
|
|
133
|
-
// to still be able to seek anywhere we want to (even ahead of the Manifest if
|
|
134
|
-
// we want to). As such, we put it at a safe default value of 2^32 excepted
|
|
135
|
-
// when the maximum position is already relatively close to that value, where
|
|
136
|
-
// we authorize exceptionally going over it.
|
|
137
|
-
newDuration = Math.max(Math.pow(2, 32), newDuration + YEAR_IN_SECONDS);
|
|
115
|
+
function setMediaSourceDuration(mediaSource, duration, isRealEndKnown) {
|
|
116
|
+
var newDuration = duration;
|
|
117
|
+
if (!isRealEndKnown) {
|
|
118
|
+
newDuration = hasIssuesWithHighMediaSourceDuration() ?
|
|
119
|
+
Infinity :
|
|
120
|
+
getMaximumLiveSeekablePosition(duration);
|
|
138
121
|
}
|
|
139
122
|
var maxBufferedEnd = 0;
|
|
140
123
|
for (var i = 0; i < mediaSource.sourceBuffers.length; i++) {
|
|
@@ -167,6 +150,9 @@ function setMediaSourceDuration(mediaSource, manifest, knownDuration) {
|
|
|
167
150
|
try {
|
|
168
151
|
log.info("Init: Updating duration", newDuration);
|
|
169
152
|
mediaSource.duration = newDuration;
|
|
153
|
+
if (mediaSource.readyState === "open" && !isFinite(newDuration)) {
|
|
154
|
+
mediaSource.setLiveSeekableRange(0, getMaximumLiveSeekablePosition(duration));
|
|
155
|
+
}
|
|
170
156
|
}
|
|
171
157
|
catch (err) {
|
|
172
158
|
log.warn("Duration Updater: Can't update duration on the MediaSource.", err instanceof Error ? err : "");
|
|
@@ -242,25 +228,36 @@ function createMediaSourceOpenReference(mediaSource, cancelSignal) {
|
|
|
242
228
|
}
|
|
243
229
|
/**
|
|
244
230
|
* Immediately tries to set the MediaSource's duration to the most appropriate
|
|
245
|
-
* one
|
|
231
|
+
* one.
|
|
246
232
|
*
|
|
247
233
|
* If it fails, wait 2 seconds and retries.
|
|
248
234
|
*
|
|
249
235
|
* @param {MediaSource} mediaSource
|
|
250
|
-
* @param {
|
|
251
|
-
* @param {
|
|
236
|
+
* @param {number} duration
|
|
237
|
+
* @param {boolean} isRealEndKnown
|
|
252
238
|
* @param {Object} cancelSignal
|
|
253
239
|
*/
|
|
254
|
-
function recursivelyForceDurationUpdate(mediaSource,
|
|
255
|
-
var res = setMediaSourceDuration(mediaSource,
|
|
240
|
+
function recursivelyForceDurationUpdate(mediaSource, duration, isRealEndKnown, cancelSignal) {
|
|
241
|
+
var res = setMediaSourceDuration(mediaSource, duration, isRealEndKnown);
|
|
256
242
|
if (res === "success" /* MediaSourceDurationUpdateStatus.Success */) {
|
|
257
243
|
return;
|
|
258
244
|
}
|
|
259
245
|
var timeoutId = setTimeout(function () {
|
|
260
246
|
unregisterClear();
|
|
261
|
-
recursivelyForceDurationUpdate(mediaSource,
|
|
247
|
+
recursivelyForceDurationUpdate(mediaSource, duration, isRealEndKnown, cancelSignal);
|
|
262
248
|
}, 2000);
|
|
263
249
|
var unregisterClear = cancelSignal.register(function () {
|
|
264
250
|
clearTimeout(timeoutId);
|
|
265
251
|
});
|
|
266
252
|
}
|
|
253
|
+
function getMaximumLiveSeekablePosition(contentLastPosition) {
|
|
254
|
+
// Some targets poorly support setting a very high number for seekable
|
|
255
|
+
// ranges.
|
|
256
|
+
// Yet, in contents whose end is not yet known (e.g. live contents), we
|
|
257
|
+
// would prefer setting a value as high as possible to still be able to
|
|
258
|
+
// seek anywhere we want to (even ahead of the Manifest if we want to).
|
|
259
|
+
// As such, we put it at a safe default value of 2^32 excepted when the
|
|
260
|
+
// maximum position is already relatively close to that value, where we
|
|
261
|
+
// authorize exceptionally going over it.
|
|
262
|
+
return Math.max(Math.pow(2, 32), contentLastPosition + YEAR_IN_SECONDS);
|
|
263
|
+
}
|
|
@@ -18,7 +18,7 @@ import { IPlayerError } from "../../../public_types";
|
|
|
18
18
|
import EventEmitter from "../../../utils/event_emitter";
|
|
19
19
|
import { IReadOnlySharedReference } from "../../../utils/reference";
|
|
20
20
|
import { PlaybackObserver } from "../../api";
|
|
21
|
-
import { IBufferType } from "../../segment_buffers";
|
|
21
|
+
import SegmentBuffersStore, { IBufferType } from "../../segment_buffers";
|
|
22
22
|
import { IStallingSituation } from "../types";
|
|
23
23
|
/**
|
|
24
24
|
* Monitor playback, trying to avoid stalling situation.
|
|
@@ -32,6 +32,7 @@ export default class RebufferingController extends EventEmitter<IRebufferingCont
|
|
|
32
32
|
/** Emit the current playback conditions */
|
|
33
33
|
private _playbackObserver;
|
|
34
34
|
private _manifest;
|
|
35
|
+
private _segmentBuffersStore;
|
|
35
36
|
private _speed;
|
|
36
37
|
private _isStarted;
|
|
37
38
|
/**
|
|
@@ -40,12 +41,23 @@ export default class RebufferingController extends EventEmitter<IRebufferingCont
|
|
|
40
41
|
*/
|
|
41
42
|
private _discontinuitiesStore;
|
|
42
43
|
private _canceller;
|
|
44
|
+
/**
|
|
45
|
+
* If set to something else than `null`, this is the DOMHighResTimestamp as
|
|
46
|
+
* outputed by `performance.now()` when playback begin to seem to not start
|
|
47
|
+
* despite having decipherable data in the buffer(s).
|
|
48
|
+
*
|
|
49
|
+
* If enough time in that condition is spent, special considerations are
|
|
50
|
+
* taken at which point `_currentFreezeTimestamp` is reset to `null`.
|
|
51
|
+
*
|
|
52
|
+
* It is also reset to `null` when and if there is no such issue anymore.
|
|
53
|
+
*/
|
|
54
|
+
private _currentFreezeTimestamp;
|
|
43
55
|
/**
|
|
44
56
|
* @param {object} playbackObserver - emit the current playback conditions.
|
|
45
57
|
* @param {Object} manifest - The Manifest of the currently-played content.
|
|
46
58
|
* @param {Object} speed - The last speed set by the user
|
|
47
59
|
*/
|
|
48
|
-
constructor(playbackObserver: PlaybackObserver, manifest: Manifest | null, speed: IReadOnlySharedReference<number>);
|
|
60
|
+
constructor(playbackObserver: PlaybackObserver, manifest: Manifest | null, segmentBuffersStore: SegmentBuffersStore | null, speed: IReadOnlySharedReference<number>);
|
|
49
61
|
start(): void;
|
|
50
62
|
/**
|
|
51
63
|
* Update information on an upcoming discontinuity for a given buffer type and
|
|
@@ -68,10 +80,32 @@ export default class RebufferingController extends EventEmitter<IRebufferingCont
|
|
|
68
80
|
* forever.
|
|
69
81
|
*/
|
|
70
82
|
destroy(): void;
|
|
83
|
+
/**
|
|
84
|
+
* Support of contents with DRM on all the platforms out there is a pain in
|
|
85
|
+
* the *ss considering all the DRM-related bugs there are.
|
|
86
|
+
*
|
|
87
|
+
* We found out a frequent issue which is to be unable to play despite having
|
|
88
|
+
* all the decryption keys to play what is currently buffered.
|
|
89
|
+
* When this happens, re-creating the buffers from scratch, with a reload, is
|
|
90
|
+
* usually sufficient to unlock the situation.
|
|
91
|
+
*
|
|
92
|
+
* Although we prefer providing more targeted fixes or telling to platform
|
|
93
|
+
* developpers to fix their implementation, it's not always possible.
|
|
94
|
+
* We thus resorted to developping an heuristic which detects such situation
|
|
95
|
+
* and reload in that case.
|
|
96
|
+
*
|
|
97
|
+
* @param {Object} observation - The last playback observation produced, it
|
|
98
|
+
* has to be recent (just triggered for example).
|
|
99
|
+
* @returns {boolean} - Returns `true` if it seems to be such kind of
|
|
100
|
+
* decipherability freeze, in which case this method already performed the
|
|
101
|
+
* right handling steps.
|
|
102
|
+
*/
|
|
103
|
+
private _checkDecipherabilityFreeze;
|
|
71
104
|
}
|
|
72
105
|
export interface IRebufferingControllerEvent {
|
|
73
106
|
stalled: IStallingSituation;
|
|
74
107
|
unstalled: null;
|
|
108
|
+
needsReload: null;
|
|
75
109
|
warning: IPlayerError;
|
|
76
110
|
}
|
|
77
111
|
/**
|