rx-player 3.27.0 → 3.27.1-dev.2022041500
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 +12 -0
- package/VERSION +1 -1
- package/dist/_esm5.processed/core/abr/abr_manager.d.ts +7 -3
- package/dist/_esm5.processed/core/abr/abr_manager.js +4 -3
- package/dist/_esm5.processed/core/abr/representation_estimator.d.ts +13 -8
- package/dist/_esm5.processed/core/abr/representation_estimator.js +4 -4
- package/dist/_esm5.processed/core/api/public_api.js +13 -14
- package/dist/_esm5.processed/core/init/content_time_boundaries_observer.d.ts +52 -0
- package/dist/_esm5.processed/core/init/content_time_boundaries_observer.js +223 -0
- package/dist/_esm5.processed/core/init/create_stream_playback_observer.js +17 -6
- package/dist/_esm5.processed/core/init/get_initial_time.d.ts +30 -5
- package/dist/_esm5.processed/core/init/get_initial_time.js +20 -13
- package/dist/_esm5.processed/core/init/load_on_media_source.js +16 -3
- package/dist/_esm5.processed/core/init/media_duration_updater.d.ts +56 -0
- package/dist/_esm5.processed/core/init/media_duration_updater.js +188 -0
- package/dist/_esm5.processed/core/stream/adaptation/adaptation_stream.d.ts +2 -5
- package/dist/_esm5.processed/core/stream/adaptation/create_representation_estimator.d.ts +3 -2
- package/dist/_esm5.processed/core/stream/adaptation/create_representation_estimator.js +3 -3
- package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +2 -22
- package/dist/_esm5.processed/core/stream/period/period_stream.d.ts +2 -5
- package/dist/_esm5.processed/core/stream/period/period_stream.js +6 -4
- package/dist/_esm5.processed/core/stream/representation/get_buffer_status.d.ts +4 -2
- package/dist/_esm5.processed/core/stream/representation/get_buffer_status.js +85 -42
- package/dist/_esm5.processed/core/stream/representation/representation_stream.js +3 -3
- package/dist/_esm5.processed/manifest/manifest.d.ts +14 -5
- package/dist/_esm5.processed/manifest/manifest.js +31 -12
- package/dist/_esm5.processed/manifest/period.d.ts +6 -0
- package/dist/_esm5.processed/manifest/period.js +9 -0
- package/dist/_esm5.processed/manifest/representation_index/types.d.ts +7 -2
- package/dist/_esm5.processed/parsers/manifest/dash/common/get_minimum_and_maximum_positions.d.ts +5 -1
- package/dist/_esm5.processed/parsers/manifest/dash/common/get_minimum_and_maximum_positions.js +6 -4
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.js +2 -1
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.d.ts +4 -0
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.js +4 -2
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.js +4 -2
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.js +3 -3
- package/dist/_esm5.processed/parsers/manifest/dash/common/parse_mpd.js +28 -20
- package/dist/_esm5.processed/parsers/manifest/local/parse_local_manifest.js +3 -2
- package/dist/_esm5.processed/parsers/manifest/metaplaylist/metaplaylist_parser.js +9 -3
- package/dist/_esm5.processed/parsers/manifest/smooth/create_parser.js +26 -17
- package/dist/_esm5.processed/parsers/manifest/types.d.ts +45 -17
- package/dist/_esm5.processed/parsers/manifest/utils/{get_maximum_position.d.ts → get_maximum_positions.d.ts} +4 -1
- package/dist/_esm5.processed/parsers/manifest/utils/{get_maximum_position.js → get_maximum_positions.js} +10 -6
- package/dist/rx-player.js +854 -351
- package/dist/rx-player.min.js +1 -1
- package/package.json +1 -1
- package/sonar-project.properties +1 -1
- package/src/core/abr/abr_manager.ts +11 -3
- package/src/core/abr/representation_estimator.ts +17 -10
- package/src/core/api/public_api.ts +13 -15
- package/src/core/init/content_time_boundaries_observer.ts +312 -0
- package/src/core/init/create_stream_playback_observer.ts +18 -7
- package/src/core/init/get_initial_time.ts +52 -19
- package/src/core/init/load_on_media_source.ts +22 -5
- package/src/core/init/media_duration_updater.ts +268 -0
- package/src/core/stream/adaptation/adaptation_stream.ts +2 -5
- package/src/core/stream/adaptation/create_representation_estimator.ts +6 -3
- package/src/core/stream/orchestrator/stream_orchestrator.ts +2 -29
- package/src/core/stream/period/period_stream.ts +12 -9
- package/src/core/stream/representation/get_buffer_status.ts +102 -41
- package/src/core/stream/representation/representation_stream.ts +3 -3
- package/src/manifest/__tests__/manifest.test.ts +94 -68
- package/src/manifest/manifest.ts +73 -33
- package/src/manifest/period.ts +10 -0
- package/src/manifest/representation_index/types.ts +7 -2
- package/src/parsers/manifest/dash/common/get_minimum_and_maximum_positions.ts +10 -5
- package/src/parsers/manifest/dash/common/indexes/base.ts +4 -3
- package/src/parsers/manifest/dash/common/indexes/list.ts +8 -1
- package/src/parsers/manifest/dash/common/indexes/template.ts +8 -3
- package/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts +7 -7
- package/src/parsers/manifest/dash/common/parse_mpd.ts +38 -20
- package/src/parsers/manifest/local/parse_local_manifest.ts +3 -2
- package/src/parsers/manifest/metaplaylist/metaplaylist_parser.ts +9 -4
- package/src/parsers/manifest/smooth/create_parser.ts +36 -18
- package/src/parsers/manifest/types.ts +45 -17
- package/src/parsers/manifest/utils/{get_maximum_position.ts → get_maximum_positions.ts} +13 -7
- package/dist/_esm5.processed/core/init/duration_updater.d.ts +0 -27
- package/dist/_esm5.processed/core/init/duration_updater.js +0 -136
- package/src/core/init/duration_updater.ts +0 -206
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import config from "../../config";
|
|
17
17
|
import log from "../../log";
|
|
18
|
+
import isNullOrUndefined from "../../utils/is_null_or_undefined";
|
|
18
19
|
/**
|
|
19
20
|
* Returns the calculated initial time for the content described by the given
|
|
20
21
|
* Manifest:
|
|
@@ -29,34 +30,40 @@ import log from "../../log";
|
|
|
29
30
|
* @returns {Number}
|
|
30
31
|
*/
|
|
31
32
|
export default function getInitialTime(manifest, lowLatencyMode, startAt) {
|
|
32
|
-
if (startAt
|
|
33
|
-
var min = manifest.
|
|
34
|
-
var max =
|
|
35
|
-
if (
|
|
33
|
+
if (!isNullOrUndefined(startAt)) {
|
|
34
|
+
var min = manifest.getMinimumSafePosition();
|
|
35
|
+
var max = void 0;
|
|
36
|
+
if (manifest.isLive) {
|
|
37
|
+
max = manifest.getLivePosition();
|
|
38
|
+
}
|
|
39
|
+
if (max === undefined) {
|
|
40
|
+
max = manifest.getMaximumSafePosition();
|
|
41
|
+
}
|
|
42
|
+
if (!isNullOrUndefined(startAt.position)) {
|
|
36
43
|
log.debug("Init: using startAt.minimumPosition");
|
|
37
44
|
return Math.max(Math.min(startAt.position, max), min);
|
|
38
45
|
}
|
|
39
|
-
else if (startAt.wallClockTime
|
|
46
|
+
else if (!isNullOrUndefined(startAt.wallClockTime)) {
|
|
40
47
|
log.debug("Init: using startAt.wallClockTime");
|
|
41
|
-
var ast = manifest.availabilityStartTime
|
|
48
|
+
var ast = manifest.availabilityStartTime === undefined ?
|
|
42
49
|
0 :
|
|
43
50
|
manifest.availabilityStartTime;
|
|
44
51
|
var position = startAt.wallClockTime - ast;
|
|
45
52
|
return Math.max(Math.min(position, max), min);
|
|
46
53
|
}
|
|
47
|
-
else if (startAt.fromFirstPosition
|
|
54
|
+
else if (!isNullOrUndefined(startAt.fromFirstPosition)) {
|
|
48
55
|
log.debug("Init: using startAt.fromFirstPosition");
|
|
49
56
|
var fromFirstPosition = startAt.fromFirstPosition;
|
|
50
57
|
return fromFirstPosition <= 0 ? min :
|
|
51
58
|
Math.min(max, min + fromFirstPosition);
|
|
52
59
|
}
|
|
53
|
-
else if (startAt.fromLastPosition
|
|
60
|
+
else if (!isNullOrUndefined(startAt.fromLastPosition)) {
|
|
54
61
|
log.debug("Init: using startAt.fromLastPosition");
|
|
55
62
|
var fromLastPosition = startAt.fromLastPosition;
|
|
56
63
|
return fromLastPosition >= 0 ? max :
|
|
57
64
|
Math.max(min, max + fromLastPosition);
|
|
58
65
|
}
|
|
59
|
-
else if (startAt.percentage
|
|
66
|
+
else if (!isNullOrUndefined(startAt.percentage)) {
|
|
60
67
|
log.debug("Init: using startAt.percentage");
|
|
61
68
|
var percentage = startAt.percentage;
|
|
62
69
|
if (percentage > 100) {
|
|
@@ -70,13 +77,13 @@ export default function getInitialTime(manifest, lowLatencyMode, startAt) {
|
|
|
70
77
|
return min + extent * ratio;
|
|
71
78
|
}
|
|
72
79
|
}
|
|
73
|
-
var minimumPosition = manifest.
|
|
80
|
+
var minimumPosition = manifest.getMinimumSafePosition();
|
|
74
81
|
if (manifest.isLive) {
|
|
75
82
|
var suggestedPresentationDelay = manifest.suggestedPresentationDelay, clockOffset = manifest.clockOffset;
|
|
76
|
-
var maximumPosition = manifest.
|
|
83
|
+
var maximumPosition = manifest.getMaximumSafePosition();
|
|
77
84
|
var liveTime = void 0;
|
|
78
85
|
var DEFAULT_LIVE_GAP = config.getCurrent().DEFAULT_LIVE_GAP;
|
|
79
|
-
if (clockOffset
|
|
86
|
+
if (clockOffset === undefined) {
|
|
80
87
|
log.info("Init: no clock offset found for a live content, " +
|
|
81
88
|
"starting close to maximum available position");
|
|
82
89
|
liveTime = maximumPosition;
|
|
@@ -84,7 +91,7 @@ export default function getInitialTime(manifest, lowLatencyMode, startAt) {
|
|
|
84
91
|
else {
|
|
85
92
|
log.info("Init: clock offset found for a live content, " +
|
|
86
93
|
"checking if we can start close to it");
|
|
87
|
-
var ast = manifest.availabilityStartTime
|
|
94
|
+
var ast = manifest.availabilityStartTime === undefined ?
|
|
88
95
|
0 :
|
|
89
96
|
manifest.availabilityStartTime;
|
|
90
97
|
var clockRelativeLiveTime = (performance.now() + clockOffset) / 1000 - ast;
|
|
@@ -18,11 +18,12 @@ import { MediaError } from "../../errors";
|
|
|
18
18
|
import log from "../../log";
|
|
19
19
|
import SegmentBuffersStore from "../segment_buffers";
|
|
20
20
|
import StreamOrchestrator from "../stream";
|
|
21
|
+
import ContentTimeBoundariesObserver from "./content_time_boundaries_observer";
|
|
21
22
|
import createStreamPlaybackObserver from "./create_stream_playback_observer";
|
|
22
|
-
import DurationUpdater from "./duration_updater";
|
|
23
23
|
import emitLoadedEvent from "./emit_loaded_event";
|
|
24
24
|
import { maintainEndOfStream } from "./end_of_stream";
|
|
25
25
|
import initialSeekAndPlay from "./initial_seek_and_play";
|
|
26
|
+
import MediaDurationUpdater from "./media_duration_updater";
|
|
26
27
|
import StallAvoider from "./stall_avoider";
|
|
27
28
|
import streamEventsEmitter from "./stream_events_emitter";
|
|
28
29
|
import updatePlaybackRate from "./update_playback_rate";
|
|
@@ -43,7 +44,7 @@ export default function createMediaSourceLoader(_a) {
|
|
|
43
44
|
return function loadContentOnMediaSource(mediaSource, initialTime, autoPlay) {
|
|
44
45
|
var _a;
|
|
45
46
|
/** Maintains the MediaSource's duration up-to-date with the Manifest */
|
|
46
|
-
var
|
|
47
|
+
var mediaDurationUpdater = new MediaDurationUpdater(manifest, mediaSource);
|
|
47
48
|
var initialPeriod = (_a = manifest.getPeriodForTime(initialTime)) !== null && _a !== void 0 ? _a : manifest.getNextPeriod(initialTime);
|
|
48
49
|
if (initialPeriod === undefined) {
|
|
49
50
|
var error_1 = new MediaError("MEDIA_STARTING_TIME_NOT_FOUND", "Wanted starting time not found in the Manifest.");
|
|
@@ -83,6 +84,17 @@ export default function createMediaSourceLoader(_a) {
|
|
|
83
84
|
return observableOf(evt);
|
|
84
85
|
}
|
|
85
86
|
}));
|
|
87
|
+
var contentTimeObserver = ContentTimeBoundariesObserver(manifest, streams$, streamObserver)
|
|
88
|
+
.pipe(mergeMap(function (evt) {
|
|
89
|
+
switch (evt.type) {
|
|
90
|
+
case "contentDurationUpdate":
|
|
91
|
+
log.debug("Init: Duration has to be updated.", evt.value);
|
|
92
|
+
mediaDurationUpdater.updateKnownDuration(evt.value);
|
|
93
|
+
return EMPTY;
|
|
94
|
+
default:
|
|
95
|
+
return observableOf(evt);
|
|
96
|
+
}
|
|
97
|
+
}));
|
|
86
98
|
/**
|
|
87
99
|
* On subscription, keep the playback speed synchronized to the speed set by
|
|
88
100
|
* the user on the media element and force a speed of `0` when the buffer is
|
|
@@ -105,7 +117,8 @@ export default function createMediaSourceLoader(_a) {
|
|
|
105
117
|
observableOf(evt) :
|
|
106
118
|
emitLoadedEvent(observation$, mediaElement, segmentBuffersStore, false);
|
|
107
119
|
}));
|
|
108
|
-
return observableMerge(
|
|
120
|
+
return observableMerge(loadingEvts$, playbackRate$, stallAvoider$, streams$, contentTimeObserver, streamEvents$).pipe(finalize(function () {
|
|
121
|
+
mediaDurationUpdater.stop();
|
|
109
122
|
// clean-up every created SegmentBuffers
|
|
110
123
|
segmentBuffersStore.disposeAll();
|
|
111
124
|
}));
|
|
@@ -0,0 +1,56 @@
|
|
|
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 Manifest from "../../manifest";
|
|
17
|
+
/**
|
|
18
|
+
* Keep the MediaSource's duration up-to-date with what is being played.
|
|
19
|
+
* @class MediaDurationUpdater
|
|
20
|
+
*/
|
|
21
|
+
export default class MediaDurationUpdater {
|
|
22
|
+
private _subscription;
|
|
23
|
+
/**
|
|
24
|
+
* The last known audio Adaptation (i.e. track) chosen for the last Period.
|
|
25
|
+
* Useful to determinate the duration of the current content.
|
|
26
|
+
* `undefined` if the audio track for the last Period has never been known yet.
|
|
27
|
+
* `null` if there are no chosen audio Adaptation.
|
|
28
|
+
*/
|
|
29
|
+
private _lastKnownDuration;
|
|
30
|
+
/**
|
|
31
|
+
* Create a new `MediaDurationUpdater` that will keep the given MediaSource's
|
|
32
|
+
* duration as soon as possible.
|
|
33
|
+
* This duration will be updated until the `stop` method is called.
|
|
34
|
+
* @param {Object} manifest - The Manifest currently played.
|
|
35
|
+
* For another content, you will have to create another `MediaDurationUpdater`.
|
|
36
|
+
* @param {MediaSource} mediaSource - The MediaSource on which the content is
|
|
37
|
+
* pushed.
|
|
38
|
+
*/
|
|
39
|
+
constructor(manifest: Manifest, mediaSource: MediaSource);
|
|
40
|
+
/**
|
|
41
|
+
* By default, the `MediaDurationUpdater` only set a safe estimate for the
|
|
42
|
+
* MediaSource's duration.
|
|
43
|
+
* A more precize duration can be set by communicating to it a more precize
|
|
44
|
+
* media duration through `updateKnownDuration`.
|
|
45
|
+
* If the duration becomes unknown, `undefined` can be given to it so the
|
|
46
|
+
* `MediaDurationUpdater` goes back to a safe estimate.
|
|
47
|
+
* @param {number | undefined} newDuration
|
|
48
|
+
*/
|
|
49
|
+
updateKnownDuration(newDuration: number | undefined): void;
|
|
50
|
+
/**
|
|
51
|
+
* Stop the `MediaDurationUpdater` from updating and free its resources.
|
|
52
|
+
* Once stopped, it is not possible to start it again, beside creating another
|
|
53
|
+
* `MediaDurationUpdater`.
|
|
54
|
+
*/
|
|
55
|
+
stop(): void;
|
|
56
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
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 { combineLatest as observableCombineLatest, distinctUntilChanged, EMPTY, fromEvent as observableFromEvent, interval as observableInterval, map, merge as observableMerge, mergeMap, of as observableOf, startWith, switchMap, timer, } from "rxjs";
|
|
17
|
+
import { onSourceOpen$, onSourceClose$, onSourceEnded$, } from "../../compat/event_listeners";
|
|
18
|
+
import log from "../../log";
|
|
19
|
+
import { fromEvent } from "../../utils/event_emitter";
|
|
20
|
+
import createSharedReference from "../../utils/reference";
|
|
21
|
+
/** Number of seconds in a regular year. */
|
|
22
|
+
var YEAR_IN_SECONDS = 365 * 24 * 3600;
|
|
23
|
+
/**
|
|
24
|
+
* Keep the MediaSource's duration up-to-date with what is being played.
|
|
25
|
+
* @class MediaDurationUpdater
|
|
26
|
+
*/
|
|
27
|
+
var MediaDurationUpdater = /** @class */ (function () {
|
|
28
|
+
/**
|
|
29
|
+
* Create a new `MediaDurationUpdater` that will keep the given MediaSource's
|
|
30
|
+
* duration as soon as possible.
|
|
31
|
+
* This duration will be updated until the `stop` method is called.
|
|
32
|
+
* @param {Object} manifest - The Manifest currently played.
|
|
33
|
+
* For another content, you will have to create another `MediaDurationUpdater`.
|
|
34
|
+
* @param {MediaSource} mediaSource - The MediaSource on which the content is
|
|
35
|
+
* pushed.
|
|
36
|
+
*/
|
|
37
|
+
function MediaDurationUpdater(manifest, mediaSource) {
|
|
38
|
+
var _this = this;
|
|
39
|
+
this._lastKnownDuration = createSharedReference(undefined);
|
|
40
|
+
this._subscription = isMediaSourceOpened$(mediaSource).pipe(switchMap(function (canUpdate) {
|
|
41
|
+
return canUpdate ? observableCombineLatest([_this._lastKnownDuration.asObservable(),
|
|
42
|
+
fromEvent(manifest, "manifestUpdate")
|
|
43
|
+
.pipe(startWith(null))]) :
|
|
44
|
+
EMPTY;
|
|
45
|
+
}), switchMap(function (_a) {
|
|
46
|
+
var lastKnownDuration = _a[0];
|
|
47
|
+
return areSourceBuffersUpdating$(mediaSource.sourceBuffers).pipe(switchMap(function (areSBUpdating) {
|
|
48
|
+
return areSBUpdating ? EMPTY :
|
|
49
|
+
recursivelyTryUpdatingDuration();
|
|
50
|
+
function recursivelyTryUpdatingDuration() {
|
|
51
|
+
var res = setMediaSourceDuration(mediaSource, manifest, lastKnownDuration);
|
|
52
|
+
if (res === "success" /* Success */) {
|
|
53
|
+
return EMPTY;
|
|
54
|
+
}
|
|
55
|
+
return timer(2000)
|
|
56
|
+
.pipe(mergeMap(function () { return recursivelyTryUpdatingDuration(); }));
|
|
57
|
+
}
|
|
58
|
+
}));
|
|
59
|
+
})).subscribe();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* By default, the `MediaDurationUpdater` only set a safe estimate for the
|
|
63
|
+
* MediaSource's duration.
|
|
64
|
+
* A more precize duration can be set by communicating to it a more precize
|
|
65
|
+
* media duration through `updateKnownDuration`.
|
|
66
|
+
* If the duration becomes unknown, `undefined` can be given to it so the
|
|
67
|
+
* `MediaDurationUpdater` goes back to a safe estimate.
|
|
68
|
+
* @param {number | undefined} newDuration
|
|
69
|
+
*/
|
|
70
|
+
MediaDurationUpdater.prototype.updateKnownDuration = function (newDuration) {
|
|
71
|
+
this._lastKnownDuration.setValue(newDuration);
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Stop the `MediaDurationUpdater` from updating and free its resources.
|
|
75
|
+
* Once stopped, it is not possible to start it again, beside creating another
|
|
76
|
+
* `MediaDurationUpdater`.
|
|
77
|
+
*/
|
|
78
|
+
MediaDurationUpdater.prototype.stop = function () {
|
|
79
|
+
this._subscription.unsubscribe();
|
|
80
|
+
};
|
|
81
|
+
return MediaDurationUpdater;
|
|
82
|
+
}());
|
|
83
|
+
export default MediaDurationUpdater;
|
|
84
|
+
/**
|
|
85
|
+
* Checks that duration can be updated on the MediaSource, and then
|
|
86
|
+
* sets it.
|
|
87
|
+
*
|
|
88
|
+
* Returns either:
|
|
89
|
+
* - the new duration it has been updated to if it has
|
|
90
|
+
* - `null` if it hasn'nt been updated
|
|
91
|
+
*
|
|
92
|
+
* @param {MediaSource} mediaSource
|
|
93
|
+
* @param {Object} manifest
|
|
94
|
+
* @returns {string}
|
|
95
|
+
*/
|
|
96
|
+
function setMediaSourceDuration(mediaSource, manifest, knownDuration) {
|
|
97
|
+
var _a;
|
|
98
|
+
var newDuration = knownDuration;
|
|
99
|
+
if (newDuration === undefined) {
|
|
100
|
+
if (manifest.isDynamic) {
|
|
101
|
+
var maxPotentialPos = (_a = manifest.getLivePosition()) !== null && _a !== void 0 ? _a : manifest.getMaximumSafePosition();
|
|
102
|
+
// Some targets poorly support setting a very high number for durations.
|
|
103
|
+
// Yet, in dynamic contents, we would prefer setting a value as high as possible
|
|
104
|
+
// to still be able to seek anywhere we want to (even ahead of the Manifest if
|
|
105
|
+
// we want to). As such, we put it at a safe default value of 2^32 excepted
|
|
106
|
+
// when the maximum position is already relatively close to that value, where
|
|
107
|
+
// we authorize exceptionally going over it.
|
|
108
|
+
newDuration = Math.max(Math.pow(2, 32), maxPotentialPos + YEAR_IN_SECONDS);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
newDuration = manifest.getMaximumSafePosition();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
var maxBufferedEnd = 0;
|
|
115
|
+
for (var i = 0; i < mediaSource.sourceBuffers.length; i++) {
|
|
116
|
+
var sourceBuffer = mediaSource.sourceBuffers[i];
|
|
117
|
+
var sbBufferedLen = sourceBuffer.buffered.length;
|
|
118
|
+
if (sbBufferedLen > 0) {
|
|
119
|
+
maxBufferedEnd = Math.max(sourceBuffer.buffered.end(sbBufferedLen - 1));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (newDuration === mediaSource.duration) {
|
|
123
|
+
return "success" /* Success */;
|
|
124
|
+
}
|
|
125
|
+
else if (maxBufferedEnd > newDuration) {
|
|
126
|
+
// We already buffered further than the duration we want to set.
|
|
127
|
+
// Keep the duration that was set at that time as a security.
|
|
128
|
+
if (maxBufferedEnd < mediaSource.duration) {
|
|
129
|
+
try {
|
|
130
|
+
log.info("Init: Updating duration to what is currently buffered", maxBufferedEnd);
|
|
131
|
+
mediaSource.duration = newDuration;
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
log.warn("Duration Updater: Can't update duration on the MediaSource.", err);
|
|
135
|
+
return "failed" /* Failed */;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return "partial" /* Partial */;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
var oldDuration = mediaSource.duration;
|
|
142
|
+
try {
|
|
143
|
+
log.info("Init: Updating duration", newDuration);
|
|
144
|
+
mediaSource.duration = newDuration;
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
log.warn("Duration Updater: Can't update duration on the MediaSource.", err);
|
|
148
|
+
return "failed" /* Failed */;
|
|
149
|
+
}
|
|
150
|
+
var deltaToExpected = Math.abs(mediaSource.duration - newDuration);
|
|
151
|
+
if (deltaToExpected >= 0.1) {
|
|
152
|
+
var deltaToBefore = Math.abs(mediaSource.duration - oldDuration);
|
|
153
|
+
return deltaToExpected < deltaToBefore ? "partial" /* Partial */ :
|
|
154
|
+
"failed" /* Failed */;
|
|
155
|
+
}
|
|
156
|
+
return "success" /* Success */;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Returns an Observable which will emit only when all the SourceBuffers ended
|
|
161
|
+
* all pending updates.
|
|
162
|
+
* @param {SourceBufferList} sourceBuffers
|
|
163
|
+
* @returns {Observable}
|
|
164
|
+
*/
|
|
165
|
+
function areSourceBuffersUpdating$(sourceBuffers) {
|
|
166
|
+
if (sourceBuffers.length === 0) {
|
|
167
|
+
return observableOf(false);
|
|
168
|
+
}
|
|
169
|
+
var sourceBufferUpdatingStatuses = [];
|
|
170
|
+
var _loop_1 = function (i) {
|
|
171
|
+
var sourceBuffer = sourceBuffers[i];
|
|
172
|
+
sourceBufferUpdatingStatuses.push(observableMerge(observableFromEvent(sourceBuffer, "updatestart").pipe(map(function () { return true; })), observableFromEvent(sourceBuffer, "update").pipe(map(function () { return false; })), observableInterval(500).pipe(map(function () { return sourceBuffer.updating; }))).pipe(startWith(sourceBuffer.updating), distinctUntilChanged()));
|
|
173
|
+
};
|
|
174
|
+
for (var i = 0; i < sourceBuffers.length; i++) {
|
|
175
|
+
_loop_1(i);
|
|
176
|
+
}
|
|
177
|
+
return observableCombineLatest(sourceBufferUpdatingStatuses).pipe(map(function (areUpdating) {
|
|
178
|
+
return areUpdating.some(function (isUpdating) { return isUpdating; });
|
|
179
|
+
}), distinctUntilChanged());
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Emit a boolean that tells if the media source is opened or not.
|
|
183
|
+
* @param {MediaSource} mediaSource
|
|
184
|
+
* @returns {Object}
|
|
185
|
+
*/
|
|
186
|
+
function isMediaSourceOpened$(mediaSource) {
|
|
187
|
+
return observableMerge(onSourceOpen$(mediaSource).pipe(map(function () { return true; })), onSourceEnded$(mediaSource).pipe(map(function () { return false; })), onSourceClose$(mediaSource).pipe(map(function () { return false; }))).pipe(startWith(mediaSource.readyState === "open"), distinctUntilChanged());
|
|
188
|
+
}
|
|
@@ -44,11 +44,8 @@ export interface IAdaptationStreamPlaybackObservation extends IRepresentationStr
|
|
|
44
44
|
isPaused: boolean;
|
|
45
45
|
/** Last "playback rate" asked by the user. */
|
|
46
46
|
speed: number;
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
* Difference between the live edge and the current position, in seconds.
|
|
50
|
-
*/
|
|
51
|
-
liveGap: number | undefined;
|
|
47
|
+
/** Theoretical maximum position on the content that can currently be played. */
|
|
48
|
+
maximumPosition: number;
|
|
52
49
|
}
|
|
53
50
|
/** Arguments given when creating a new `AdaptationStream`. */
|
|
54
51
|
export interface IAdaptationStreamArguments {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import { Observable, Subject } from "rxjs";
|
|
17
|
-
import Manifest, { Adaptation } from "../../../manifest";
|
|
17
|
+
import Manifest, { Adaptation, Period } from "../../../manifest";
|
|
18
18
|
import ABRManager, { IABREstimate, IABRManagerPlaybackObservation, IABRStreamEvents } from "../../abr";
|
|
19
19
|
/**
|
|
20
20
|
* Create an "estimator$" Observable which will emit which Representation (from
|
|
@@ -33,8 +33,9 @@ import ABRManager, { IABREstimate, IABRManagerPlaybackObservation, IABRStreamEve
|
|
|
33
33
|
* @param {Observable} observation$
|
|
34
34
|
* @returns {Object}
|
|
35
35
|
*/
|
|
36
|
-
export default function createRepresentationEstimator(
|
|
36
|
+
export default function createRepresentationEstimator(content: {
|
|
37
37
|
manifest: Manifest;
|
|
38
|
+
period: Period;
|
|
38
39
|
adaptation: Adaptation;
|
|
39
40
|
}, abrManager: ABRManager, observation$: Observable<IABRManagerPlaybackObservation>): {
|
|
40
41
|
estimator$: Observable<IABREstimate>;
|
|
@@ -33,8 +33,8 @@ import { fromEvent } from "../../../utils/event_emitter";
|
|
|
33
33
|
* @param {Observable} observation$
|
|
34
34
|
* @returns {Object}
|
|
35
35
|
*/
|
|
36
|
-
export default function createRepresentationEstimator(
|
|
37
|
-
var manifest =
|
|
36
|
+
export default function createRepresentationEstimator(content, abrManager, observation$) {
|
|
37
|
+
var manifest = content.manifest, adaptation = content.adaptation;
|
|
38
38
|
var abrFeedbacks$ = new Subject();
|
|
39
39
|
var estimator$ = observableMerge(
|
|
40
40
|
// subscribe "first" (hack as it is a merge here) to event
|
|
@@ -60,7 +60,7 @@ export default function createRepresentationEstimator(_a, abrManager, observatio
|
|
|
60
60
|
}
|
|
61
61
|
return true;
|
|
62
62
|
}), switchMap(function (playableRepresentations) {
|
|
63
|
-
return abrManager.get$(
|
|
63
|
+
return abrManager.get$(content, playableRepresentations, observation$, abrFeedbacks$);
|
|
64
64
|
}));
|
|
65
65
|
return { estimator$: estimator$, abrFeedbacks$: abrFeedbacks$ };
|
|
66
66
|
}
|
|
@@ -84,26 +84,8 @@ export default function StreamOrchestrator(content, playbackObserver, abrManager
|
|
|
84
84
|
maxBufferAhead$: maxBufferAhead.asObservable().pipe(map(function (val) { return Math.min(val, defaultMaxAhead); })),
|
|
85
85
|
});
|
|
86
86
|
});
|
|
87
|
-
// trigger warnings when the wanted time is before or after the manifest's
|
|
88
|
-
// segments
|
|
89
|
-
var outOfManifest$ = playbackObserver.observe(true).pipe(filterMap(function (_a) {
|
|
90
|
-
var position = _a.position, wantedTimeOffset = _a.wantedTimeOffset;
|
|
91
|
-
var offsetedPosition = wantedTimeOffset + position;
|
|
92
|
-
if (offsetedPosition < manifest.getMinimumPosition()) {
|
|
93
|
-
var warning = new MediaError("MEDIA_TIME_BEFORE_MANIFEST", "The current position is behind the " +
|
|
94
|
-
"earliest time announced in the Manifest.");
|
|
95
|
-
return EVENTS.warning(warning);
|
|
96
|
-
}
|
|
97
|
-
else if (offsetedPosition > manifest.getMaximumPosition()) {
|
|
98
|
-
var warning = new MediaError("MEDIA_TIME_AFTER_MANIFEST", "The current position is after the latest " +
|
|
99
|
-
"time announced in the Manifest.");
|
|
100
|
-
return EVENTS.warning(warning);
|
|
101
|
-
}
|
|
102
|
-
return null;
|
|
103
|
-
}, null));
|
|
104
|
-
var bufferTypes = segmentBuffersStore.getBufferTypes();
|
|
105
87
|
// Every PeriodStreams for every possible types
|
|
106
|
-
var streamsArray =
|
|
88
|
+
var streamsArray = segmentBuffersStore.getBufferTypes().map(function (bufferType) {
|
|
107
89
|
return manageEveryStreams(bufferType, initialPeriod)
|
|
108
90
|
.pipe(deferSubscriptions(), share());
|
|
109
91
|
});
|
|
@@ -122,9 +104,7 @@ export default function StreamOrchestrator(content, playbackObserver, abrManager
|
|
|
122
104
|
}), distinctUntilChanged(), map(function (emitEndOfStream) {
|
|
123
105
|
return emitEndOfStream ? EVENTS.endOfStream() : EVENTS.resumeStream();
|
|
124
106
|
}));
|
|
125
|
-
return observableMerge.apply(void 0, __spreadArray(__spreadArray([], streamsArray, false), [activePeriodChanged$,
|
|
126
|
-
endOfStream$,
|
|
127
|
-
outOfManifest$], false));
|
|
107
|
+
return observableMerge.apply(void 0, __spreadArray(__spreadArray([], streamsArray, false), [activePeriodChanged$, endOfStream$], false));
|
|
128
108
|
/**
|
|
129
109
|
* Manage creation and removal of Streams for every Periods for a given type.
|
|
130
110
|
*
|
|
@@ -41,11 +41,8 @@ export interface IPeriodStreamPlaybackObservation {
|
|
|
41
41
|
* which we actually want to download segments for.
|
|
42
42
|
*/
|
|
43
43
|
wantedTimeOffset: number;
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
* Difference between the live edge and the current position, in seconds.
|
|
47
|
-
*/
|
|
48
|
-
liveGap: number | undefined;
|
|
44
|
+
/** Theoretical maximum position on the content that can currently be played. */
|
|
45
|
+
maximumPosition: number;
|
|
49
46
|
}
|
|
50
47
|
/** Arguments required by the `PeriodStream`. */
|
|
51
48
|
export interface IPeriodStreamArguments {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { catchError, concat as observableConcat, defer as observableDefer, EMPTY, ignoreElements, map, merge as observableMerge, mergeMap, of as observableOf, ReplaySubject, startWith, switchMap, } from "rxjs";
|
|
17
17
|
import config from "../../../config";
|
|
18
|
-
import { formatError } from "../../../errors";
|
|
18
|
+
import { formatError, MediaError, } from "../../../errors";
|
|
19
19
|
import log from "../../../log";
|
|
20
20
|
import objectAssign from "../../../utils/object_assign";
|
|
21
21
|
import { getLeftSizeOfRange } from "../../../utils/ranges";
|
|
@@ -166,9 +166,11 @@ function createOrReuseSegmentBuffer(segmentBuffersStore, bufferType, adaptation,
|
|
|
166
166
|
* @returns {string}
|
|
167
167
|
*/
|
|
168
168
|
function getFirstDeclaredMimeType(adaptation) {
|
|
169
|
-
var representations = adaptation.
|
|
170
|
-
if (representations
|
|
171
|
-
|
|
169
|
+
var representations = adaptation.getPlayableRepresentations();
|
|
170
|
+
if (representations.length === 0) {
|
|
171
|
+
var noRepErr = new MediaError("NO_PLAYABLE_REPRESENTATION", "No Representation in the chosen " +
|
|
172
|
+
adaptation.type + " Adaptation can be played");
|
|
173
|
+
throw noRepErr;
|
|
172
174
|
}
|
|
173
175
|
return representations[0].getMimeTypeString();
|
|
174
176
|
}
|
|
@@ -56,9 +56,11 @@ export interface IBufferStatus {
|
|
|
56
56
|
* be filled by any segment, even in the future.
|
|
57
57
|
*
|
|
58
58
|
* @param {Object} content
|
|
59
|
-
* @param {
|
|
59
|
+
* @param {number} initialWantedTime
|
|
60
|
+
* @param {Object} playbackObserver
|
|
60
61
|
* @param {number|undefined} fastSwitchThreshold
|
|
61
62
|
* @param {number} bufferGoal
|
|
63
|
+
* @param {number} maxBufferSize
|
|
62
64
|
* @param {Object} segmentBuffer
|
|
63
65
|
* @returns {Object}
|
|
64
66
|
*/
|
|
@@ -67,4 +69,4 @@ export default function getBufferStatus(content: {
|
|
|
67
69
|
manifest: Manifest;
|
|
68
70
|
period: Period;
|
|
69
71
|
representation: Representation;
|
|
70
|
-
},
|
|
72
|
+
}, initialWantedTime: number, playbackObserver: IReadOnlyPlaybackObserver<unknown>, fastSwitchThreshold: number | undefined, bufferGoal: number, maxBufferSize: number, segmentBuffer: SegmentBuffer): IBufferStatus;
|