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
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import config from "../../../config";
|
|
23
|
+
import { MediaError } from "../../../errors";
|
|
23
24
|
import log from "../../../log";
|
|
24
25
|
import Manifest, {
|
|
25
26
|
Adaptation,
|
|
@@ -27,7 +28,6 @@ import Manifest, {
|
|
|
27
28
|
Representation,
|
|
28
29
|
} from "../../../manifest";
|
|
29
30
|
import {
|
|
30
|
-
IAudioRepresentation,
|
|
31
31
|
IAudioRepresentationsSwitchingMode,
|
|
32
32
|
IAudioTrack,
|
|
33
33
|
IAudioTrackSwitchingMode,
|
|
@@ -38,18 +38,19 @@ import {
|
|
|
38
38
|
IBrokenRepresentationsLockContext,
|
|
39
39
|
IPeriod,
|
|
40
40
|
ITextTrack,
|
|
41
|
-
IVideoRepresentation,
|
|
42
41
|
IVideoRepresentationsSwitchingMode,
|
|
43
42
|
IVideoTrack,
|
|
44
43
|
IVideoTrackSwitchingMode,
|
|
44
|
+
IPlayerError,
|
|
45
45
|
} from "../../../public_types";
|
|
46
46
|
import arrayFind from "../../../utils/array_find";
|
|
47
47
|
import assert from "../../../utils/assert";
|
|
48
48
|
import EventEmitter from "../../../utils/event_emitter";
|
|
49
|
+
import isNullOrUndefined from "../../../utils/is_null_or_undefined";
|
|
50
|
+
import objectAssign from "../../../utils/object_assign";
|
|
49
51
|
import createSharedReference, {
|
|
50
52
|
ISharedReference,
|
|
51
53
|
} from "../../../utils/reference";
|
|
52
|
-
import takeFirstSet from "../../../utils/take_first_set";
|
|
53
54
|
import {
|
|
54
55
|
IAdaptationChoice,
|
|
55
56
|
IRepresentationsChoice,
|
|
@@ -156,7 +157,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
|
|
|
156
157
|
const stillHere = textAdaptations
|
|
157
158
|
.some(a => a.id === curWantedTextTrack.adaptation.id);
|
|
158
159
|
if (!stillHere) {
|
|
159
|
-
log.warn("
|
|
160
|
+
log.warn("TS: Chosen text Adaptation not available anymore");
|
|
160
161
|
const periodInfo = this._storedPeriodInfo[i];
|
|
161
162
|
periodInfo.text.storedSettings = null;
|
|
162
163
|
this.trigger("trackUpdate", { period: toExposedPeriod(newPeriod),
|
|
@@ -182,7 +183,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
|
|
|
182
183
|
const stillHere = videoAdaptations
|
|
183
184
|
.some(a => a.id === curWantedVideoTrack.adaptation.id);
|
|
184
185
|
if (!stillHere) {
|
|
185
|
-
log.warn("
|
|
186
|
+
log.warn("TS: Chosen video Adaptation not available anymore");
|
|
186
187
|
const periodItem = this._storedPeriodInfo[i];
|
|
187
188
|
let storedSettings : IVideoStoredSettings;
|
|
188
189
|
if (videoAdaptations.length === 0) {
|
|
@@ -224,7 +225,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
|
|
|
224
225
|
const stillHere = audioAdaptations
|
|
225
226
|
.some(a => a.id === curWantedAudioTrack.adaptation.id);
|
|
226
227
|
if (!stillHere) {
|
|
227
|
-
log.warn("
|
|
228
|
+
log.warn("TS: Chosen audio Adaptation not available anymore");
|
|
228
229
|
const periodItem = this._storedPeriodInfo[i];
|
|
229
230
|
const storedSettings = audioAdaptations.length === 0 ?
|
|
230
231
|
null :
|
|
@@ -323,20 +324,62 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
|
|
|
323
324
|
}
|
|
324
325
|
|
|
325
326
|
if (periodObj[bufferType].dispatcher !== null) {
|
|
326
|
-
log.error(`
|
|
327
|
+
log.error(`TS: Subject already added for ${bufferType} ` +
|
|
327
328
|
`and Period ${period.start}`);
|
|
328
329
|
return;
|
|
329
330
|
}
|
|
330
331
|
const trackSetting = periodObj[bufferType].storedSettings;
|
|
331
|
-
const dispatcher = new TrackDispatcher(manifest, adaptationRef
|
|
332
|
+
const dispatcher = new TrackDispatcher(manifest, adaptationRef);
|
|
332
333
|
periodObj[bufferType].dispatcher = dispatcher;
|
|
334
|
+
dispatcher.addEventListener("noPlayableRepresentation", () => {
|
|
335
|
+
const nextAdaptation = arrayFind(period.getAdaptationsForType(bufferType), (a) => {
|
|
336
|
+
const playableRepresentations = a.getPlayableRepresentations();
|
|
337
|
+
return playableRepresentations.length > 0;
|
|
338
|
+
});
|
|
339
|
+
if (nextAdaptation === undefined) {
|
|
340
|
+
const noRepErr = new MediaError("NO_PLAYABLE_REPRESENTATION",
|
|
341
|
+
`No ${bufferType} Representation can be played`,
|
|
342
|
+
{ adaptation: undefined });
|
|
343
|
+
this.trigger("error", noRepErr);
|
|
344
|
+
this.dispose();
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
let typeInfo = getPeriodItem(this._storedPeriodInfo, period.id)?.[bufferType];
|
|
348
|
+
if (isNullOrUndefined(typeInfo)) {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const switchingMode = bufferType === "audio" ?
|
|
352
|
+
this._defaultAudioTrackSwitchingMode :
|
|
353
|
+
"reload";
|
|
354
|
+
const storedSettings = { adaptation: nextAdaptation,
|
|
355
|
+
switchingMode,
|
|
356
|
+
lockedRepresentations: createSharedReference(null) };
|
|
357
|
+
typeInfo.storedSettings = storedSettings;
|
|
358
|
+
this.trigger("trackUpdate", { period: toExposedPeriod(period),
|
|
359
|
+
trackType: bufferType,
|
|
360
|
+
reason: "no-playable-representation" });
|
|
361
|
+
|
|
362
|
+
// The previous event trigger could have had side-effects, so we
|
|
363
|
+
// re-check if we're still mostly in the same state
|
|
364
|
+
if (this._isDisposed) {
|
|
365
|
+
return; // Someone disposed the `TracksStore` on the previous side-effect
|
|
366
|
+
}
|
|
367
|
+
typeInfo = getPeriodItem(this._storedPeriodInfo, period.id)?.[bufferType];
|
|
368
|
+
if (isNullOrUndefined(typeInfo) || typeInfo.storedSettings !== storedSettings) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
typeInfo.dispatcher?.updateTrack(storedSettings);
|
|
372
|
+
});
|
|
333
373
|
dispatcher.addEventListener("noPlayableLockedRepresentation", () => {
|
|
374
|
+
// TODO check that it doesn't already lead to segment loading or MediaSource
|
|
375
|
+
// reloading
|
|
334
376
|
trackSetting?.lockedRepresentations.setValue(null);
|
|
335
377
|
this.trigger("brokenRepresentationsLock", { period: { id: period.id,
|
|
336
378
|
start: period.start,
|
|
337
379
|
end: period.end },
|
|
338
380
|
trackType: bufferType });
|
|
339
381
|
});
|
|
382
|
+
dispatcher.start(trackSetting);
|
|
340
383
|
}
|
|
341
384
|
|
|
342
385
|
/**
|
|
@@ -351,7 +394,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
|
|
|
351
394
|
) : void {
|
|
352
395
|
const periodIndex = findPeriodIndex(this._storedPeriodInfo, period);
|
|
353
396
|
if (periodIndex === undefined) {
|
|
354
|
-
log.warn(`
|
|
397
|
+
log.warn(`TS: ${bufferType} not found for period`,
|
|
355
398
|
period.start);
|
|
356
399
|
return;
|
|
357
400
|
}
|
|
@@ -359,7 +402,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
|
|
|
359
402
|
const periodObj = this._storedPeriodInfo[periodIndex];
|
|
360
403
|
const choiceItem = periodObj[bufferType];
|
|
361
404
|
if (choiceItem?.dispatcher === null) {
|
|
362
|
-
log.warn(`
|
|
405
|
+
log.warn(`TS: TrackDispatcher already removed for ${bufferType} ` +
|
|
363
406
|
`and Period ${period.start}`);
|
|
364
407
|
return;
|
|
365
408
|
}
|
|
@@ -684,10 +727,12 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
|
|
|
684
727
|
* `null` if audio tracks were disabled and `undefined` if the Period is not
|
|
685
728
|
* known.
|
|
686
729
|
*/
|
|
687
|
-
public getChosenAudioTrack(
|
|
730
|
+
public getChosenAudioTrack(
|
|
731
|
+
periodObj : ITMPeriodObject
|
|
732
|
+
) : IAudioTrack | null {
|
|
688
733
|
return periodObj.audio.storedSettings === null ?
|
|
689
734
|
null :
|
|
690
|
-
|
|
735
|
+
periodObj.audio.storedSettings.adaptation.toAudioTrack(true);
|
|
691
736
|
}
|
|
692
737
|
|
|
693
738
|
/**
|
|
@@ -705,7 +750,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
|
|
|
705
750
|
) : ITextTrack | null {
|
|
706
751
|
return periodObj.text.storedSettings === null ?
|
|
707
752
|
null :
|
|
708
|
-
|
|
753
|
+
periodObj.text.storedSettings.adaptation.toTextTrack();
|
|
709
754
|
}
|
|
710
755
|
|
|
711
756
|
/**
|
|
@@ -725,7 +770,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
|
|
|
725
770
|
return null;
|
|
726
771
|
}
|
|
727
772
|
|
|
728
|
-
return
|
|
773
|
+
return periodObj.video.storedSettings.adaptation.toVideoTrack(true);
|
|
729
774
|
}
|
|
730
775
|
|
|
731
776
|
/**
|
|
@@ -746,21 +791,9 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
|
|
|
746
791
|
null;
|
|
747
792
|
return periodObj.period.getSupportedAdaptations("audio")
|
|
748
793
|
.map((adaptation) => {
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
audioDescription: adaptation.isAudioDescription === true,
|
|
753
|
-
id: adaptation.id,
|
|
754
|
-
active: currentId === null ? false :
|
|
755
|
-
currentId === adaptation.id,
|
|
756
|
-
representations: adaptation.getPlayableRepresentations()
|
|
757
|
-
.map(parseAudioRepresentation),
|
|
758
|
-
label: adaptation.label,
|
|
759
|
-
};
|
|
760
|
-
if (adaptation.isDub === true) {
|
|
761
|
-
formatted.dub = true;
|
|
762
|
-
}
|
|
763
|
-
return formatted;
|
|
794
|
+
const active = currentId === null ? false :
|
|
795
|
+
currentId === adaptation.id;
|
|
796
|
+
return objectAssign(adaptation.toAudioTrack(true), { active });
|
|
764
797
|
});
|
|
765
798
|
}
|
|
766
799
|
|
|
@@ -783,19 +816,9 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
|
|
|
783
816
|
|
|
784
817
|
return periodObj.period.getSupportedAdaptations("text")
|
|
785
818
|
.map((adaptation) => {
|
|
786
|
-
const
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
closedCaption: adaptation.isClosedCaption === true,
|
|
790
|
-
id: adaptation.id,
|
|
791
|
-
active: currentId === null ? false :
|
|
792
|
-
currentId === adaptation.id,
|
|
793
|
-
label: adaptation.label,
|
|
794
|
-
};
|
|
795
|
-
if (adaptation.isForcedSubtitles !== undefined) {
|
|
796
|
-
formatted.forced = adaptation.isForcedSubtitles;
|
|
797
|
-
}
|
|
798
|
-
return formatted;
|
|
819
|
+
const active = currentId === null ? false :
|
|
820
|
+
currentId === adaptation.id;
|
|
821
|
+
return objectAssign(adaptation.toTextTrack(), { active });
|
|
799
822
|
});
|
|
800
823
|
}
|
|
801
824
|
|
|
@@ -818,38 +841,21 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
|
|
|
818
841
|
|
|
819
842
|
return periodObj.period.getSupportedAdaptations("video")
|
|
820
843
|
.map((adaptation) => {
|
|
821
|
-
const
|
|
822
|
-
|
|
844
|
+
const active = currentId === null ? false :
|
|
845
|
+
currentId === adaptation.id;
|
|
846
|
+
const track = adaptation.toVideoTrack(true);
|
|
847
|
+
const trickModeTracks = track.trickModeTracks !== undefined ?
|
|
848
|
+
track.trickModeTracks.map((trickModeAdaptation) => {
|
|
823
849
|
const isActive = currentId === null ? false :
|
|
824
850
|
currentId === trickModeAdaptation.id;
|
|
825
|
-
|
|
826
|
-
.map(parseVideoRepresentation);
|
|
827
|
-
const trickMode : IAvailableVideoTrack = { id: trickModeAdaptation.id,
|
|
828
|
-
representations,
|
|
829
|
-
isTrickModeTrack: true,
|
|
830
|
-
active: isActive };
|
|
831
|
-
if (trickModeAdaptation.isSignInterpreted === true) {
|
|
832
|
-
trickMode.signInterpreted = true;
|
|
833
|
-
}
|
|
834
|
-
return trickMode;
|
|
851
|
+
return objectAssign(trickModeAdaptation, { active: isActive });
|
|
835
852
|
}) :
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
const formatted: IAvailableVideoTrack = {
|
|
839
|
-
id: adaptation.id,
|
|
840
|
-
active: currentId === null ? false :
|
|
841
|
-
currentId === adaptation.id,
|
|
842
|
-
representations: adaptation.getPlayableRepresentations()
|
|
843
|
-
.map(parseVideoRepresentation),
|
|
844
|
-
label: adaptation.label,
|
|
845
|
-
};
|
|
846
|
-
if (adaptation.isSignInterpreted === true) {
|
|
847
|
-
formatted.signInterpreted = true;
|
|
848
|
-
}
|
|
853
|
+
[];
|
|
854
|
+
const availableTrack = objectAssign(track, { active });
|
|
849
855
|
if (trickModeTracks !== undefined) {
|
|
850
|
-
|
|
856
|
+
availableTrack.trickModeTracks = trickModeTracks;
|
|
851
857
|
}
|
|
852
|
-
return
|
|
858
|
+
return availableTrack;
|
|
853
859
|
});
|
|
854
860
|
}
|
|
855
861
|
|
|
@@ -1082,17 +1088,6 @@ function getPeriodItem(
|
|
|
1082
1088
|
}
|
|
1083
1089
|
}
|
|
1084
1090
|
|
|
1085
|
-
/**
|
|
1086
|
-
* Parse video Representation into a IVideoRepresentation.
|
|
1087
|
-
* @param {Object} representation
|
|
1088
|
-
* @returns {Object}
|
|
1089
|
-
*/
|
|
1090
|
-
function parseVideoRepresentation(
|
|
1091
|
-
{ id, bitrate, frameRate, width, height, codec, hdrInfo } : Representation
|
|
1092
|
-
) : IVideoRepresentation {
|
|
1093
|
-
return { id, bitrate, frameRate, width, height, codec, hdrInfo };
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
1091
|
/**
|
|
1097
1092
|
* A `ITMPeriodObject` should only be removed once all References linked to it
|
|
1098
1093
|
* do not exist anymore, to keep the possibility of making track choices.
|
|
@@ -1108,17 +1103,6 @@ function isPeriodItemRemovable(
|
|
|
1108
1103
|
periodObj.video?.dispatcher === null;
|
|
1109
1104
|
}
|
|
1110
1105
|
|
|
1111
|
-
/**
|
|
1112
|
-
* Parse audio Representation into a ITMAudioRepresentation.
|
|
1113
|
-
* @param {Object} representation
|
|
1114
|
-
* @returns {Object}
|
|
1115
|
-
*/
|
|
1116
|
-
function parseAudioRepresentation(
|
|
1117
|
-
{ id, bitrate, codec } : Representation
|
|
1118
|
-
) : IAudioRepresentation {
|
|
1119
|
-
return { id, bitrate, codec };
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
1106
|
function getRightVideoTrack(
|
|
1123
1107
|
adaptation : Adaptation,
|
|
1124
1108
|
isTrickModeEnabled : boolean
|
|
@@ -1197,82 +1181,6 @@ function generatePeriodInfo(
|
|
|
1197
1181
|
dispatcher: null } };
|
|
1198
1182
|
}
|
|
1199
1183
|
|
|
1200
|
-
/**
|
|
1201
|
-
* Format Adaptation structure into the format awaited by the API.
|
|
1202
|
-
* @param {Object} a
|
|
1203
|
-
* @returns {Object}
|
|
1204
|
-
*/
|
|
1205
|
-
function toTextTrack(a : Adaptation) : ITextTrack {
|
|
1206
|
-
const formatted : ITextTrack = {
|
|
1207
|
-
language: a.language ?? "",
|
|
1208
|
-
normalized: a.normalizedLanguage ?? "",
|
|
1209
|
-
closedCaption: a.isClosedCaption === true,
|
|
1210
|
-
id: a.id,
|
|
1211
|
-
label: a.label,
|
|
1212
|
-
};
|
|
1213
|
-
if (a.isForcedSubtitles !== undefined) {
|
|
1214
|
-
formatted.forced = a.isForcedSubtitles;
|
|
1215
|
-
}
|
|
1216
|
-
return formatted;
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
/**
|
|
1220
|
-
* Format Adaptation structure into the format awaited by the API.
|
|
1221
|
-
* @param {Object} a
|
|
1222
|
-
* @returns {Object}
|
|
1223
|
-
*/
|
|
1224
|
-
function toVideoTrack(a : Adaptation) : IVideoTrack {
|
|
1225
|
-
const trickModeTracks = a.trickModeTracks !== undefined ?
|
|
1226
|
-
a.trickModeTracks.map((trickModeAdaptation) => {
|
|
1227
|
-
const representations = trickModeAdaptation.getPlayableRepresentations()
|
|
1228
|
-
.map(parseVideoRepresentation);
|
|
1229
|
-
const trickMode : IVideoTrack = { id: trickModeAdaptation.id,
|
|
1230
|
-
representations,
|
|
1231
|
-
isTrickModeTrack: true };
|
|
1232
|
-
if (trickModeAdaptation.isSignInterpreted === true) {
|
|
1233
|
-
trickMode.signInterpreted = true;
|
|
1234
|
-
}
|
|
1235
|
-
return trickMode;
|
|
1236
|
-
}) :
|
|
1237
|
-
undefined;
|
|
1238
|
-
|
|
1239
|
-
const videoTrack: IVideoTrack = {
|
|
1240
|
-
id: a.id,
|
|
1241
|
-
representations: a.getPlayableRepresentations().map(parseVideoRepresentation),
|
|
1242
|
-
label: a.label,
|
|
1243
|
-
};
|
|
1244
|
-
if (a.isSignInterpreted === true) {
|
|
1245
|
-
videoTrack.signInterpreted = true;
|
|
1246
|
-
}
|
|
1247
|
-
if (a.isTrickModeTrack === true) {
|
|
1248
|
-
videoTrack.isTrickModeTrack = true;
|
|
1249
|
-
}
|
|
1250
|
-
if (trickModeTracks !== undefined) {
|
|
1251
|
-
videoTrack.trickModeTracks = trickModeTracks;
|
|
1252
|
-
}
|
|
1253
|
-
return videoTrack;
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
/**
|
|
1257
|
-
* Convert an audio Adaptation into an audio track.
|
|
1258
|
-
* @param {object|null} adaptation - Audio adaptation
|
|
1259
|
-
* @returns {object|null} - corresponding audio track object.
|
|
1260
|
-
*/
|
|
1261
|
-
function toAudioTrack(adaptation : Adaptation) : IAudioTrack {
|
|
1262
|
-
const audioTrack : IAudioTrack = {
|
|
1263
|
-
language: takeFirstSet<string>(adaptation.language, ""),
|
|
1264
|
-
normalized: takeFirstSet<string>(adaptation.normalizedLanguage, ""),
|
|
1265
|
-
audioDescription: adaptation.isAudioDescription === true,
|
|
1266
|
-
id: adaptation.id,
|
|
1267
|
-
representations: adaptation.representations.map(parseAudioRepresentation),
|
|
1268
|
-
label: adaptation.label,
|
|
1269
|
-
};
|
|
1270
|
-
if (adaptation.isDub === true) {
|
|
1271
|
-
audioTrack.dub = true;
|
|
1272
|
-
}
|
|
1273
|
-
return audioTrack;
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
1184
|
function toExposedPeriod(p: Period) : IPeriod {
|
|
1277
1185
|
return { start: p.start, end: p.end, id: p.id };
|
|
1278
1186
|
}
|
|
@@ -1435,6 +1343,8 @@ interface ITracksStoreEvents {
|
|
|
1435
1343
|
newAvailablePeriods : IPeriod[];
|
|
1436
1344
|
brokenRepresentationsLock : IBrokenRepresentationsLockContext;
|
|
1437
1345
|
trackUpdate : ITrackUpdateEventPayload;
|
|
1346
|
+
error : unknown;
|
|
1347
|
+
warning : IPlayerError;
|
|
1438
1348
|
}
|
|
1439
1349
|
|
|
1440
1350
|
export interface IAudioRepresentationsLockSettings {
|
package/src/core/api/utils.ts
CHANGED
|
@@ -70,6 +70,32 @@ export function emitSeekEvents(
|
|
|
70
70
|
}, { includeLastObservation: true, clearSignal: cancelSignal });
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
/**
|
|
74
|
+
* @param {HTMLMediaElement} mediaElement
|
|
75
|
+
* @param {function} onPlay - Callback called when a play operation has started
|
|
76
|
+
* on `mediaElement`.
|
|
77
|
+
* @param {function} onPause - Callback called when a pause operation has
|
|
78
|
+
* started on `mediaElement`.
|
|
79
|
+
* @param {Object} cancelSignal - When triggered, stop calling callbacks and
|
|
80
|
+
* remove all listeners this function has registered.
|
|
81
|
+
*/
|
|
82
|
+
export function emitPlayPauseEvents(
|
|
83
|
+
mediaElement : HTMLMediaElement | null,
|
|
84
|
+
onPlay: () => void,
|
|
85
|
+
onPause: () => void,
|
|
86
|
+
cancelSignal : CancellationSignal
|
|
87
|
+
) : void {
|
|
88
|
+
if (cancelSignal.isCancelled() || mediaElement === null) {
|
|
89
|
+
return ;
|
|
90
|
+
}
|
|
91
|
+
mediaElement.addEventListener("play", onPlay);
|
|
92
|
+
mediaElement.addEventListener("pause", onPause);
|
|
93
|
+
cancelSignal.register(() => {
|
|
94
|
+
mediaElement.removeEventListener("play", onPlay);
|
|
95
|
+
mediaElement.removeEventListener("pause", onPause);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
73
99
|
/** Player state dictionnary. */
|
|
74
100
|
export const enum PLAYER_STATES {
|
|
75
101
|
STOPPED = "STOPPED",
|
|
@@ -113,7 +113,12 @@ export default function SessionEventsListener(
|
|
|
113
113
|
if (isNullOrUndefined(licenseObject)) {
|
|
114
114
|
log.info("DRM: No license given, skipping session.update");
|
|
115
115
|
} else {
|
|
116
|
-
|
|
116
|
+
try {
|
|
117
|
+
return updateSessionWithMessage(session, licenseObject);
|
|
118
|
+
} catch (err) {
|
|
119
|
+
manualCanceller.cancel();
|
|
120
|
+
callbacks.onError(err);
|
|
121
|
+
}
|
|
117
122
|
}
|
|
118
123
|
})
|
|
119
124
|
.catch((err : unknown) => {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import log from "../../../log";
|
|
17
18
|
import LoadedSessionsStore from "./loaded_sessions_store";
|
|
18
19
|
|
|
19
20
|
/**
|
|
@@ -32,7 +33,7 @@ export default async function cleanOldLoadedSessions(
|
|
|
32
33
|
if (limit < 0 || limit >= loadedSessionsStore.getLength()) {
|
|
33
34
|
return ;
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
+
log.info("DRM: LSS cache limit exceeded", limit, loadedSessionsStore.getLength());
|
|
36
37
|
const proms : Array<Promise<unknown>> = [];
|
|
37
38
|
const entries = loadedSessionsStore.getAll().slice(); // clone
|
|
38
39
|
const toDelete = entries.length - limit;
|
|
@@ -63,6 +63,7 @@ export default class LoadedSessionsStore {
|
|
|
63
63
|
sessionType : MediaKeySessionType
|
|
64
64
|
) : IStoredSessionEntry {
|
|
65
65
|
const keySessionRecord = new KeySessionRecord(initData);
|
|
66
|
+
log.debug("DRM-LSS: calling `createSession`", sessionType);
|
|
66
67
|
const mediaKeySession = this._mediaKeys.createSession(sessionType);
|
|
67
68
|
const entry = { mediaKeySession,
|
|
68
69
|
sessionType,
|
|
@@ -73,6 +74,8 @@ export default class LoadedSessionsStore {
|
|
|
73
74
|
if (!isNullOrUndefined(mediaKeySession.closed)) {
|
|
74
75
|
mediaKeySession.closed
|
|
75
76
|
.then(() => {
|
|
77
|
+
log.info("DRM-LSS: session was closed, removing it.",
|
|
78
|
+
mediaKeySession.sessionId);
|
|
76
79
|
const index = this.getIndex(keySessionRecord);
|
|
77
80
|
if (index >= 0 &&
|
|
78
81
|
this._storage[index].mediaKeySession === mediaKeySession)
|
|
@@ -86,8 +89,8 @@ export default class LoadedSessionsStore {
|
|
|
86
89
|
});
|
|
87
90
|
}
|
|
88
91
|
|
|
89
|
-
log.debug("DRM-LSS: Add MediaKeySession", entry.sessionType);
|
|
90
92
|
this._storage.push({ ...entry });
|
|
93
|
+
log.debug("DRM-LSS: MediaKeySession added", entry.sessionType, this._storage.length);
|
|
91
94
|
return entry;
|
|
92
95
|
}
|
|
93
96
|
|
|
@@ -111,6 +114,8 @@ export default class LoadedSessionsStore {
|
|
|
111
114
|
if (stored.keySessionRecord.isCompatibleWith(initializationData)) {
|
|
112
115
|
this._storage.splice(i, 1);
|
|
113
116
|
this._storage.push(stored);
|
|
117
|
+
log.debug("DRM-LSS: Reusing session:",
|
|
118
|
+
stored.mediaKeySession.sessionId, stored.sessionType);
|
|
114
119
|
return { ...stored };
|
|
115
120
|
}
|
|
116
121
|
}
|
|
@@ -332,6 +337,8 @@ export default class LoadedSessionsStore {
|
|
|
332
337
|
for (let i = this._storage.length - 1; i >= 0; i--) {
|
|
333
338
|
const stored = this._storage[i];
|
|
334
339
|
if (stored.mediaKeySession === mediaKeySession) {
|
|
340
|
+
log.debug("DRM-LSS: Removing session without closing it",
|
|
341
|
+
mediaKeySession.sessionId);
|
|
335
342
|
this._storage.splice(i, 1);
|
|
336
343
|
return true;
|
|
337
344
|
}
|
|
@@ -84,6 +84,7 @@ export default class DirectFileContentInitializer extends ContentInitializer {
|
|
|
84
84
|
* events when it cannot, as well as "unstalled" events when it get out of one.
|
|
85
85
|
*/
|
|
86
86
|
const rebufferingController = new RebufferingController(playbackObserver,
|
|
87
|
+
null,
|
|
87
88
|
null,
|
|
88
89
|
speed);
|
|
89
90
|
rebufferingController.addEventListener("stalled", (evt) =>
|
|
@@ -67,7 +67,7 @@ import getInitialTime, {
|
|
|
67
67
|
import getLoadedReference from "./utils/get_loaded_reference";
|
|
68
68
|
import performInitialSeekAndPlay from "./utils/initial_seek_and_play";
|
|
69
69
|
import initializeContentDecryption from "./utils/initialize_content_decryption";
|
|
70
|
-
import
|
|
70
|
+
import MediaSourceDurationUpdater from "./utils/media_source_duration_updater";
|
|
71
71
|
import RebufferingController from "./utils/rebuffering_controller";
|
|
72
72
|
import streamEventsEmitter from "./utils/stream_events_emitter";
|
|
73
73
|
import listenToMediaError from "./utils/throw_on_media_error";
|
|
@@ -352,7 +352,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
352
352
|
if (initCanceller.isUsed()) {
|
|
353
353
|
return;
|
|
354
354
|
}
|
|
355
|
-
triggerEvent("reloadingMediaSource",
|
|
355
|
+
triggerEvent("reloadingMediaSource", reloadOrder);
|
|
356
356
|
if (initCanceller.isUsed()) {
|
|
357
357
|
return;
|
|
358
358
|
}
|
|
@@ -448,9 +448,20 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
448
448
|
|
|
449
449
|
const rebufferingController = this._createRebufferingController(playbackObserver,
|
|
450
450
|
manifest,
|
|
451
|
+
segmentBuffersStore,
|
|
451
452
|
speed,
|
|
452
453
|
cancelSignal);
|
|
453
|
-
|
|
454
|
+
rebufferingController.addEventListener("needsReload", () => {
|
|
455
|
+
// NOTE couldn't both be always calculated at event destination?
|
|
456
|
+
// Maybe there are exceptions?
|
|
457
|
+
const position = initialSeekPerformed.getValue() ?
|
|
458
|
+
playbackObserver.getCurrentTime() :
|
|
459
|
+
initialTime;
|
|
460
|
+
const autoplay = initialPlayPerformed.getValue() ?
|
|
461
|
+
!playbackObserver.getIsPaused() :
|
|
462
|
+
autoPlay;
|
|
463
|
+
onReloadOrder({ position, autoPlay: autoplay });
|
|
464
|
+
}, cancelSignal);
|
|
454
465
|
const contentTimeBoundariesObserver = this
|
|
455
466
|
._createContentTimeBoundariesObserver(manifest,
|
|
456
467
|
mediaSource,
|
|
@@ -498,8 +509,36 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
498
509
|
*/
|
|
499
510
|
function handleStreamOrchestratorCallbacks() : IStreamOrchestratorCallbacks {
|
|
500
511
|
return {
|
|
501
|
-
needsBufferFlush: () =>
|
|
502
|
-
|
|
512
|
+
needsBufferFlush: () => {
|
|
513
|
+
const seekedTime = mediaElement.currentTime + 0.001;
|
|
514
|
+
playbackObserver.setCurrentTime(seekedTime);
|
|
515
|
+
|
|
516
|
+
// Seek again once data begins to be buffered.
|
|
517
|
+
// This is sadly necessary on some browsers to avoid decoding
|
|
518
|
+
// issues after a flush.
|
|
519
|
+
//
|
|
520
|
+
// NOTE: there's in theory a potential race condition in the following
|
|
521
|
+
// logic as the callback could be called when media data is still
|
|
522
|
+
// being removed by the browser - which is an asynchronous process.
|
|
523
|
+
// The following condition checking for buffered data could thus lead
|
|
524
|
+
// to a false positive where we're actually checking previous data.
|
|
525
|
+
// For now, such scenario is avoided by setting the
|
|
526
|
+
// `includeLastObservation` option to `false` and calling
|
|
527
|
+
// `needsBufferFlush` once MSE media removal operations have been
|
|
528
|
+
// explicitely validated by the browser, but that's a complex and easy
|
|
529
|
+
// to break system.
|
|
530
|
+
playbackObserver.listen((obs, stopListening) => {
|
|
531
|
+
if (
|
|
532
|
+
// Data is buffered around the current position
|
|
533
|
+
obs.currentRange !== null ||
|
|
534
|
+
// Or, for whatever reason, playback is already advancing
|
|
535
|
+
obs.position > seekedTime + 0.1
|
|
536
|
+
) {
|
|
537
|
+
stopListening();
|
|
538
|
+
playbackObserver.setCurrentTime(obs.position + 0.001);
|
|
539
|
+
}
|
|
540
|
+
}, { includeLastObservation: false, clearSignal: cancelSignal });
|
|
541
|
+
},
|
|
503
542
|
|
|
504
543
|
streamStatusUpdate(value) {
|
|
505
544
|
// Announce discontinuities if found
|
|
@@ -640,9 +679,9 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
640
679
|
cancelSignal : CancellationSignal
|
|
641
680
|
) : ContentTimeBoundariesObserver {
|
|
642
681
|
/** Maintains the MediaSource's duration up-to-date with the Manifest */
|
|
643
|
-
const
|
|
682
|
+
const mediaSourceDurationUpdater = new MediaSourceDurationUpdater(mediaSource);
|
|
644
683
|
cancelSignal.register(() => {
|
|
645
|
-
|
|
684
|
+
mediaSourceDurationUpdater.stopUpdating();
|
|
646
685
|
});
|
|
647
686
|
/** Allows to cancel a pending `end-of-stream` operation. */
|
|
648
687
|
let endOfStreamCanceller : TaskCanceller | null = null;
|
|
@@ -660,8 +699,7 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
660
699
|
this.trigger("activePeriodChanged", { period });
|
|
661
700
|
});
|
|
662
701
|
contentTimeBoundariesObserver.addEventListener("durationUpdate", (newDuration) => {
|
|
663
|
-
|
|
664
|
-
mediaDurationUpdater.updateKnownDuration(newDuration);
|
|
702
|
+
mediaSourceDurationUpdater.updateDuration(newDuration.duration, newDuration.isEnd);
|
|
665
703
|
});
|
|
666
704
|
contentTimeBoundariesObserver.addEventListener("endOfStream", () => {
|
|
667
705
|
if (endOfStreamCanceller === null) {
|
|
@@ -678,6 +716,9 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
678
716
|
endOfStreamCanceller = null;
|
|
679
717
|
}
|
|
680
718
|
});
|
|
719
|
+
const currentDuration = contentTimeBoundariesObserver.getCurrentDuration();
|
|
720
|
+
mediaSourceDurationUpdater.updateDuration(currentDuration.duration,
|
|
721
|
+
currentDuration.isEnd);
|
|
681
722
|
return contentTimeBoundariesObserver;
|
|
682
723
|
}
|
|
683
724
|
|
|
@@ -702,11 +743,13 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
702
743
|
private _createRebufferingController(
|
|
703
744
|
playbackObserver : PlaybackObserver,
|
|
704
745
|
manifest : Manifest,
|
|
746
|
+
segmentBuffersStore : SegmentBuffersStore,
|
|
705
747
|
speed : IReadOnlySharedReference<number>,
|
|
706
748
|
cancelSignal : CancellationSignal
|
|
707
749
|
) : RebufferingController {
|
|
708
750
|
const rebufferingController = new RebufferingController(playbackObserver,
|
|
709
751
|
manifest,
|
|
752
|
+
segmentBuffersStore,
|
|
710
753
|
speed);
|
|
711
754
|
// Bubble-up events
|
|
712
755
|
rebufferingController.addEventListener("stalled",
|
package/src/core/init/types.ts
CHANGED
|
@@ -120,7 +120,15 @@ export interface IContentInitializerEvents {
|
|
|
120
120
|
* Event sent when we're starting attach a new MediaSource to the media element
|
|
121
121
|
* (after removing the previous one).
|
|
122
122
|
*/
|
|
123
|
-
reloadingMediaSource:
|
|
123
|
+
reloadingMediaSource: {
|
|
124
|
+
/** The position we're reloading at, in seconds. */
|
|
125
|
+
position: number;
|
|
126
|
+
/**
|
|
127
|
+
* If `true`, we'll play directly after finishing the reloading operation.
|
|
128
|
+
* If `false`, we'll be paused after it.
|
|
129
|
+
*/
|
|
130
|
+
autoPlay: boolean;
|
|
131
|
+
};
|
|
124
132
|
/** Event sent after the player stalled. */
|
|
125
133
|
stalled : IStallingSituation;
|
|
126
134
|
/** Event sent when the player goes out of a stalling situation. */
|