rx-player 3.28.0-dev.2022063000 → 3.28.1-dev.2022083000
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/.github/workflows/checks.yml +20 -18
- package/CHANGELOG.md +14 -2
- package/VERSION +1 -1
- package/dist/_esm5.processed/compat/eme/load_session.d.ts +5 -6
- package/dist/_esm5.processed/compat/eme/load_session.js +5 -6
- package/dist/_esm5.processed/compat/event_listeners.js +5 -0
- package/dist/_esm5.processed/core/api/media_element_track_choice_manager.js +1 -1
- package/dist/_esm5.processed/core/api/public_api.js +2 -2
- package/dist/_esm5.processed/core/decrypt/create_session.js +33 -4
- package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.d.ts +14 -0
- package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.js +25 -0
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.d.ts +1 -1
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.js +1 -1
- package/dist/_esm5.processed/core/init/content_time_boundaries_observer.js +110 -38
- package/dist/_esm5.processed/core/stream/representation/check_for_discontinuity.js +21 -9
- package/dist/_esm5.processed/core/stream/representation/get_buffer_status.js +21 -29
- package/dist/_esm5.processed/errors/encrypted_media_error.d.ts +1 -2
- package/dist/_esm5.processed/errors/encrypted_media_error.js +0 -1
- package/dist/_esm5.processed/errors/error_codes.d.ts +6 -1
- package/dist/_esm5.processed/errors/media_error.d.ts +1 -2
- package/dist/_esm5.processed/errors/media_error.js +0 -1
- package/dist/_esm5.processed/errors/network_error.d.ts +1 -2
- package/dist/_esm5.processed/errors/network_error.js +0 -1
- package/dist/_esm5.processed/errors/other_error.d.ts +1 -2
- package/dist/_esm5.processed/errors/other_error.js +0 -1
- package/dist/_esm5.processed/manifest/manifest.d.ts +1 -1
- package/dist/_esm5.processed/manifest/manifest.js +1 -1
- package/dist/_esm5.processed/manifest/representation_index/static.d.ts +21 -6
- package/dist/_esm5.processed/manifest/representation_index/static.js +26 -8
- package/dist/_esm5.processed/manifest/representation_index/types.d.ts +55 -44
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.d.ts +21 -8
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.js +25 -10
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.d.ts +26 -12
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.js +26 -13
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.d.ts +23 -7
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.js +65 -22
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.d.ts +20 -3
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.js +57 -7
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/{is_period_fulfilled.d.ts → utils.d.ts} +3 -6
- package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/{is_period_fulfilled.js → utils.js} +4 -8
- package/dist/_esm5.processed/parsers/manifest/dash/common/parse_periods.js +1 -1
- package/dist/_esm5.processed/parsers/manifest/local/parse_local_manifest.js +5 -8
- package/dist/_esm5.processed/parsers/manifest/local/representation_index.d.ts +21 -8
- package/dist/_esm5.processed/parsers/manifest/local/representation_index.js +49 -14
- package/dist/_esm5.processed/parsers/manifest/local/types.d.ts +16 -0
- package/dist/_esm5.processed/parsers/manifest/metaplaylist/representation_index.d.ts +20 -6
- package/dist/_esm5.processed/parsers/manifest/metaplaylist/representation_index.js +28 -10
- package/dist/_esm5.processed/parsers/manifest/smooth/create_parser.js +4 -4
- package/dist/_esm5.processed/parsers/manifest/smooth/representation_index.d.ts +21 -12
- package/dist/_esm5.processed/parsers/manifest/smooth/representation_index.js +39 -14
- package/dist/_esm5.processed/parsers/manifest/utils/get_first_time_from_adaptation.js +1 -1
- package/dist/_esm5.processed/parsers/manifest/utils/get_last_time_from_adaptation.js +1 -1
- package/dist/_esm5.processed/transports/metaplaylist/pipelines.js +0 -2
- package/dist/_esm5.processed/transports/smooth/segment_loader.js +1 -1
- package/dist/_esm5.processed/transports/types.d.ts +1 -1
- package/dist/_esm5.processed/utils/deep_merge.d.ts +1 -1
- package/dist/_esm5.processed/utils/deep_merge.js +6 -5
- package/dist/_esm5.processed/utils/task_canceller.d.ts +0 -3
- package/dist/_esm5.processed/utils/task_canceller.js +0 -3
- package/dist/mpd-parser.wasm +0 -0
- package/dist/rx-player.js +1390 -1059
- package/dist/rx-player.min.js +1 -1
- package/jest.config.js +5 -0
- package/package.json +31 -30
- package/sonar-project.properties +1 -1
- package/src/compat/eme/load_session.ts +5 -6
- package/src/compat/event_listeners.ts +5 -0
- package/src/core/api/media_element_track_choice_manager.ts +1 -1
- package/src/core/api/public_api.ts +2 -2
- package/src/core/decrypt/create_session.ts +28 -2
- package/src/core/decrypt/utils/loaded_sessions_store.ts +29 -0
- package/src/core/fetchers/segment/segment_fetcher.ts +1 -1
- package/src/core/init/content_time_boundaries_observer.ts +116 -42
- package/src/core/stream/representation/check_for_discontinuity.ts +28 -10
- package/src/core/stream/representation/get_buffer_status.ts +27 -34
- package/src/errors/encrypted_media_error.ts +1 -2
- package/src/errors/error_codes.ts +2 -2
- package/src/errors/media_error.ts +1 -2
- package/src/errors/network_error.ts +1 -2
- package/src/errors/other_error.ts +1 -2
- package/src/manifest/__tests__/adaptation.test.ts +4 -3
- package/src/manifest/__tests__/representation.test.ts +4 -3
- package/src/manifest/manifest.ts +1 -1
- package/src/manifest/representation_index/__tests__/static.test.ts +5 -4
- package/src/manifest/representation_index/static.ts +28 -9
- package/src/manifest/representation_index/types.ts +62 -46
- package/src/parsers/manifest/dash/common/indexes/base.ts +27 -11
- package/src/parsers/manifest/dash/common/indexes/list.ts +32 -15
- package/src/parsers/manifest/dash/common/indexes/template.ts +73 -27
- package/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts +60 -8
- package/src/parsers/manifest/dash/common/indexes/{is_period_fulfilled.ts → utils.ts} +4 -13
- package/src/parsers/manifest/dash/common/parse_periods.ts +1 -1
- package/src/parsers/manifest/local/parse_local_manifest.ts +8 -20
- package/src/parsers/manifest/local/representation_index.ts +51 -16
- package/src/parsers/manifest/local/types.ts +13 -0
- package/src/parsers/manifest/metaplaylist/representation_index.ts +31 -11
- package/src/parsers/manifest/smooth/create_parser.ts +4 -4
- package/src/parsers/manifest/smooth/representation_index.ts +40 -15
- package/src/parsers/manifest/utils/__tests__/get_first_time_from_adaptations.test.ts +4 -3
- package/src/parsers/manifest/utils/__tests__/get_last_time_from_adaptation.test.ts +4 -3
- package/src/parsers/manifest/utils/get_first_time_from_adaptation.ts +1 -1
- package/src/parsers/manifest/utils/get_last_time_from_adaptation.ts +1 -1
- package/src/transports/metaplaylist/pipelines.ts +0 -2
- package/src/transports/smooth/segment_loader.ts +1 -1
- package/src/transports/types.ts +1 -1
- package/src/utils/__tests__/initialization_segment_cache.test.ts +7 -0
- package/src/utils/deep_merge.ts +7 -4
- package/src/utils/task_canceller.ts +0 -3
|
@@ -54,27 +54,29 @@ jobs:
|
|
|
54
54
|
- run: node tests/integration/run.js --bchromehl
|
|
55
55
|
- run: npm run test:memory
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
# Windows seems to be a lot less stable for some reason.
|
|
58
|
+
# TODO debug?
|
|
59
|
+
# integration_windows:
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
# runs-on: windows-latest
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
# strategy:
|
|
64
|
+
# matrix:
|
|
65
|
+
# node-version: [16.x]
|
|
66
|
+
# # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
65
67
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
68
|
+
# steps:
|
|
69
|
+
# - uses: actions/checkout@v2
|
|
70
|
+
# - name: Use Node.js ${{ matrix.node-version }}
|
|
71
|
+
# uses: actions/setup-node@v2
|
|
72
|
+
# with:
|
|
73
|
+
# node-version: ${{ matrix.node-version }}
|
|
74
|
+
# cache: 'npm'
|
|
75
|
+
# - run: npm install
|
|
76
|
+
# # Firefox seems to have issue with integration tests on GitHub actions only
|
|
77
|
+
# # TODO to check
|
|
78
|
+
# - run: node tests/integration/run.js --bchromehl
|
|
79
|
+
# - run: npm run test:memory
|
|
78
80
|
|
|
79
81
|
# MacOS seems to be a lot less stable for some reason.
|
|
80
82
|
# TODO debug?
|
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## v3.28.1-dev.2022083000 (2022-08-30)
|
|
4
|
+
|
|
5
|
+
### Bug fixes
|
|
6
|
+
|
|
7
|
+
- DRM: When using persistent licenses, create new MediaKeySession when `load` resolves with `false`, instead of relying the same, to fix issues with such persistent sessions [#1139]
|
|
8
|
+
|
|
9
|
+
### Other improvements
|
|
10
|
+
|
|
11
|
+
- In the experimental "local" transport, add `incomingRanges` property to signal the time ranges of remaining data, allowing better discontinuity handling and duration estimates for sill-loading dowloaded contents [#1151]
|
|
12
|
+
|
|
13
|
+
## v3.28.0 (2022-07-12)
|
|
4
14
|
|
|
5
15
|
### Features
|
|
6
16
|
|
|
@@ -10,13 +20,14 @@
|
|
|
10
20
|
### Bug fixes
|
|
11
21
|
|
|
12
22
|
- Use the first **compatible** codec of the current AdaptationSet when creating a SourceBuffer [#1094]
|
|
13
|
-
- DASH/DRM: Fix potential infinite rebuffering when a KID is not
|
|
23
|
+
- DASH/DRM: Fix potential infinite rebuffering when a KID is not announced in the MPD [#1113]
|
|
14
24
|
- DRM: Fix quality fallback when loading a content whose license has been cached under an extended `singleLicensePer` setting and when starting (and staying) with a quality whose key id is not in it [#1133]
|
|
15
25
|
- DASH: Avoid infinite loop due to rounding errors while parsing multi-Periods MPDs [#1111, #1110]
|
|
16
26
|
- After a `RELOADING` state, stay in `PAUSED` if the media element was paused synchronously before the side-effect which triggered the reloading (usually coming from the API) was perform [#1132]
|
|
17
27
|
- Fix issue with `maxVideoBufferSize` setting which could lead to too much data being buffered [#1125]
|
|
18
28
|
- Prevent possibility of requests loops and infinite rebuffering when a pushed segment is always completely and immediately garbage collected by the browser [#1123]
|
|
19
29
|
- DASH: Fix potential rare memory leak when stopping the content after it has reloaded at least once [#1135]
|
|
30
|
+
- Directfile: Properly announce the audio track's `audioDescription` accessibility attribute in directfile mode on Safari [#1136]
|
|
20
31
|
- DASH: Fix issues that could arise if a segment is calculated to start at a negative position [#1122]
|
|
21
32
|
- DASH: Fix possibility of wrong segments being requested when a SegmentTimeline in a given Period (whose Period@end is set) had an S@r set to `-1` at its end [#1098]
|
|
22
33
|
- DASH: If the first `<S>` has its S@t attribute not set, make as if it is set to `0` [#1118]
|
|
@@ -24,6 +35,7 @@
|
|
|
24
35
|
### Other improvements
|
|
25
36
|
|
|
26
37
|
- TTML: Add support for percent based thickness for textOutline in TTML Subtitles [#1108]
|
|
38
|
+
- Improve TypeScript's language servers auto import feature with the RxPlayer by better redirecting to the exported type [#1126]
|
|
27
39
|
- If seeking after the last potential position, load last segments before ending [#1097]
|
|
28
40
|
- The duration set on the media element is now only relative to the current chosen tracks (it was previously relative to all potential track). This allows to seek later when switching e.g. to a longer video track [#1102]
|
|
29
41
|
- Errors coming from an HTMLMediaElement now have the browser's error message if it exists [#1112]
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.28.
|
|
1
|
+
3.28.1-dev.2022083000
|
|
@@ -18,14 +18,13 @@ import { ICustomMediaKeySession } from "./custom_media_keys";
|
|
|
18
18
|
* Load a persistent session, based on its `sessionId`, on the given
|
|
19
19
|
* MediaKeySession.
|
|
20
20
|
*
|
|
21
|
-
* Returns
|
|
22
|
-
* - true if the persistent MediaKeySession was found and loaded
|
|
23
|
-
* - false if no persistent MediaKeySession was found with that `sessionId`.
|
|
24
|
-
* Then completes.
|
|
21
|
+
* Returns a Promise which resolves with:
|
|
22
|
+
* - `true` if the persistent MediaKeySession was found and loaded
|
|
23
|
+
* - `false` if no persistent MediaKeySession was found with that `sessionId`.
|
|
25
24
|
*
|
|
26
|
-
* The
|
|
25
|
+
* The Promise rejects if anything goes wrong in the process.
|
|
27
26
|
* @param {MediaKeySession} session
|
|
28
27
|
* @param {string} sessionId
|
|
29
|
-
* @returns {
|
|
28
|
+
* @returns {Promise.<boolean>}
|
|
30
29
|
*/
|
|
31
30
|
export default function loadSession(session: MediaKeySession | ICustomMediaKeySession, sessionId: string): Promise<boolean>;
|
|
@@ -55,15 +55,14 @@ var EME_WAITING_DELAY_LOADED_SESSION_EMPTY_KEYSTATUSES = 100;
|
|
|
55
55
|
* Load a persistent session, based on its `sessionId`, on the given
|
|
56
56
|
* MediaKeySession.
|
|
57
57
|
*
|
|
58
|
-
* Returns
|
|
59
|
-
* - true if the persistent MediaKeySession was found and loaded
|
|
60
|
-
* - false if no persistent MediaKeySession was found with that `sessionId`.
|
|
61
|
-
* Then completes.
|
|
58
|
+
* Returns a Promise which resolves with:
|
|
59
|
+
* - `true` if the persistent MediaKeySession was found and loaded
|
|
60
|
+
* - `false` if no persistent MediaKeySession was found with that `sessionId`.
|
|
62
61
|
*
|
|
63
|
-
* The
|
|
62
|
+
* The Promise rejects if anything goes wrong in the process.
|
|
64
63
|
* @param {MediaKeySession} session
|
|
65
64
|
* @param {string} sessionId
|
|
66
|
-
* @returns {
|
|
65
|
+
* @returns {Promise.<boolean>}
|
|
67
66
|
*/
|
|
68
67
|
export default function loadSession(session, sessionId) {
|
|
69
68
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -156,10 +156,12 @@ function getPageActivityRef(stopListening) {
|
|
|
156
156
|
var ref = createSharedReference(true);
|
|
157
157
|
stopListening.register(function () {
|
|
158
158
|
clearTimeout(currentTimeout);
|
|
159
|
+
currentTimeout = undefined;
|
|
159
160
|
ref.finish();
|
|
160
161
|
});
|
|
161
162
|
isDocVisibleRef.onUpdate(function onDocVisibilityChange(isVisible) {
|
|
162
163
|
clearTimeout(currentTimeout); // clear potential previous timeout
|
|
164
|
+
currentTimeout = undefined;
|
|
163
165
|
if (!isVisible) {
|
|
164
166
|
var INACTIVITY_DELAY = config.getCurrent().INACTIVITY_DELAY;
|
|
165
167
|
currentTimeout = window.setTimeout(function () {
|
|
@@ -239,6 +241,7 @@ function getVideoVisibilityRef(pipStatus, stopListening) {
|
|
|
239
241
|
var ref = createSharedReference(true);
|
|
240
242
|
stopListening.register(function () {
|
|
241
243
|
clearTimeout(currentTimeout);
|
|
244
|
+
currentTimeout = undefined;
|
|
242
245
|
ref.finish();
|
|
243
246
|
});
|
|
244
247
|
isDocVisibleRef.onUpdate(checkCurrentVisibility, { clearSignal: stopListening });
|
|
@@ -246,6 +249,8 @@ function getVideoVisibilityRef(pipStatus, stopListening) {
|
|
|
246
249
|
checkCurrentVisibility();
|
|
247
250
|
return ref;
|
|
248
251
|
function checkCurrentVisibility() {
|
|
252
|
+
clearTimeout(currentTimeout);
|
|
253
|
+
currentTimeout = undefined;
|
|
249
254
|
if (pipStatus.getValue().isEnabled || isDocVisibleRef.getValue()) {
|
|
250
255
|
ref.setValueIfChanged(true);
|
|
251
256
|
}
|
|
@@ -69,7 +69,7 @@ function createAudioTracks(audioTracks) {
|
|
|
69
69
|
occurences.toString();
|
|
70
70
|
languagesOccurences[language] = occurences + 1;
|
|
71
71
|
var track = { language: audioTrack.language, id: id, normalized: normalizeLanguage(audioTrack.language),
|
|
72
|
-
audioDescription:
|
|
72
|
+
audioDescription: audioTrack.kind === "descriptions",
|
|
73
73
|
representations: [] };
|
|
74
74
|
newAudioTracks.push({ track: track, nativeTrack: audioTrack });
|
|
75
75
|
}
|
|
@@ -88,7 +88,7 @@ var Player = /** @class */ (function (_super) {
|
|
|
88
88
|
// Workaround to support Firefox autoplay on FF 42.
|
|
89
89
|
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
|
|
90
90
|
videoElement.preload = "auto";
|
|
91
|
-
_this.version = /* PLAYER_VERSION */ "3.28.
|
|
91
|
+
_this.version = /* PLAYER_VERSION */ "3.28.1-dev.2022083000";
|
|
92
92
|
_this.log = log;
|
|
93
93
|
_this.state = "STOPPED";
|
|
94
94
|
_this.videoElement = videoElement;
|
|
@@ -2295,5 +2295,5 @@ var Player = /** @class */ (function (_super) {
|
|
|
2295
2295
|
};
|
|
2296
2296
|
return Player;
|
|
2297
2297
|
}(EventEmitter));
|
|
2298
|
-
Player.version = /* PLAYER_VERSION */ "3.28.
|
|
2298
|
+
Player.version = /* PLAYER_VERSION */ "3.28.1-dev.2022083000";
|
|
2299
2299
|
export default Player;
|
|
@@ -110,7 +110,7 @@ function createAndTryToRetrievePersistentSession(loadedSessionsStore, persistent
|
|
|
110
110
|
*/
|
|
111
111
|
function recreatePersistentSession() {
|
|
112
112
|
return __awaiter(this, void 0, void 0, function () {
|
|
113
|
-
var persistentEntry, newEntry;
|
|
113
|
+
var persistentEntry, err_2, newEntry;
|
|
114
114
|
return __generator(this, function (_a) {
|
|
115
115
|
switch (_a.label) {
|
|
116
116
|
case 0:
|
|
@@ -122,9 +122,30 @@ function createAndTryToRetrievePersistentSession(loadedSessionsStore, persistent
|
|
|
122
122
|
if (persistentEntry !== null) {
|
|
123
123
|
persistentSessionsStore.delete(persistentEntry.sessionId);
|
|
124
124
|
}
|
|
125
|
-
|
|
125
|
+
_a.label = 1;
|
|
126
126
|
case 1:
|
|
127
|
+
_a.trys.push([1, 3, , 4]);
|
|
128
|
+
return [4 /*yield*/, loadedSessionsStore.closeSession(entry.mediaKeySession)];
|
|
129
|
+
case 2:
|
|
127
130
|
_a.sent();
|
|
131
|
+
return [3 /*break*/, 4];
|
|
132
|
+
case 3:
|
|
133
|
+
err_2 = _a.sent();
|
|
134
|
+
// From reading the EME specification in details, it seems that a
|
|
135
|
+
// `MediaKeySession`'s ability to be closed is tightly linked to its
|
|
136
|
+
// possession of a "sanitized session ID" set as `sessionId`.
|
|
137
|
+
// This is never clearly stated however and I'm (Paul B.) always afraid of
|
|
138
|
+
// breaking compatibility when it comes to EME code.
|
|
139
|
+
// So we still try to close the `MediaKeySession` in any case, only, if it
|
|
140
|
+
// fails and it didn't had any `sessionId` set, we just ignore the error.
|
|
141
|
+
// Note that trying to close the `MediaKeySession` might incur some delays
|
|
142
|
+
// in those rare cases.
|
|
143
|
+
if (entry.mediaKeySession.sessionId !== "") {
|
|
144
|
+
throw err_2;
|
|
145
|
+
}
|
|
146
|
+
loadedSessionsStore.removeSessionWithoutClosingIt(entry.mediaKeySession);
|
|
147
|
+
return [3 /*break*/, 4];
|
|
148
|
+
case 4:
|
|
128
149
|
if (cancelSignal.cancellationError !== null) {
|
|
129
150
|
throw cancelSignal.cancellationError;
|
|
130
151
|
}
|
|
@@ -135,7 +156,7 @@ function createAndTryToRetrievePersistentSession(loadedSessionsStore, persistent
|
|
|
135
156
|
});
|
|
136
157
|
});
|
|
137
158
|
}
|
|
138
|
-
var entry, storedEntry, hasLoadedSession, err_1;
|
|
159
|
+
var entry, storedEntry, hasLoadedSession, newEntry, err_1;
|
|
139
160
|
return __generator(this, function (_a) {
|
|
140
161
|
switch (_a.label) {
|
|
141
162
|
case 0:
|
|
@@ -158,8 +179,16 @@ function createAndTryToRetrievePersistentSession(loadedSessionsStore, persistent
|
|
|
158
179
|
if (!hasLoadedSession) {
|
|
159
180
|
log.warn("DRM: No data stored for the loaded session");
|
|
160
181
|
persistentSessionsStore.delete(storedEntry.sessionId);
|
|
182
|
+
// The EME specification is kind of implicit about it but it seems from my
|
|
183
|
+
// understanding (Paul B.) that a MediaKeySession on wich a `load` attempt
|
|
184
|
+
// did not succeed due to the loaded session not being found by the
|
|
185
|
+
// browser/CDM, should neither be used anymore nor closed.
|
|
186
|
+
// Thus, we're creating another `"persistent-license"` `MediaKeySession`
|
|
187
|
+
// in that specific case.
|
|
188
|
+
loadedSessionsStore.removeSessionWithoutClosingIt(entry.mediaKeySession);
|
|
189
|
+
newEntry = loadedSessionsStore.createSession(initData, "persistent-license");
|
|
161
190
|
return [2 /*return*/, { type: "created-session" /* MediaKeySessionLoadingType.Created */,
|
|
162
|
-
value:
|
|
191
|
+
value: newEntry }];
|
|
163
192
|
}
|
|
164
193
|
if (hasLoadedSession && isSessionUsable(entry.mediaKeySession)) {
|
|
165
194
|
persistentSessionsStore.add(initData, initData.keyIds, entry.mediaKeySession);
|
|
@@ -106,6 +106,20 @@ export default class LoadedSessionsStore {
|
|
|
106
106
|
* @returns {Promise}
|
|
107
107
|
*/
|
|
108
108
|
closeAllSessions(): Promise<void>;
|
|
109
|
+
/**
|
|
110
|
+
* Find the given `MediaKeySession` in the `LoadedSessionsStore` and removes
|
|
111
|
+
* any reference to it without actually closing it.
|
|
112
|
+
*
|
|
113
|
+
* Returns `true` if the given `mediaKeySession` has been found and removed,
|
|
114
|
+
* `false` otherwise.
|
|
115
|
+
*
|
|
116
|
+
* Note that this may create a `MediaKeySession` leakage in the wrong
|
|
117
|
+
* conditions, cases where this method should be called should be very
|
|
118
|
+
* carefully evaluated.
|
|
119
|
+
* @param {MediaKeySession} mediaKeySession
|
|
120
|
+
* @returns {boolean}
|
|
121
|
+
*/
|
|
122
|
+
removeSessionWithoutClosingIt(mediaKeySession: MediaKeySession | ICustomMediaKeySession): boolean;
|
|
109
123
|
/**
|
|
110
124
|
* Get the index of a stored MediaKeySession entry based on its
|
|
111
125
|
* `KeySessionRecord`.
|
|
@@ -62,6 +62,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
62
62
|
};
|
|
63
63
|
import { closeSession, generateKeyRequest, loadSession, } from "../../../compat";
|
|
64
64
|
import log from "../../../log";
|
|
65
|
+
import assert from "../../../utils/assert";
|
|
65
66
|
import isNullOrUndefined from "../../../utils/is_null_or_undefined";
|
|
66
67
|
import KeySessionRecord from "./key_session_record";
|
|
67
68
|
/**
|
|
@@ -346,6 +347,30 @@ var LoadedSessionsStore = /** @class */ (function () {
|
|
|
346
347
|
});
|
|
347
348
|
});
|
|
348
349
|
};
|
|
350
|
+
/**
|
|
351
|
+
* Find the given `MediaKeySession` in the `LoadedSessionsStore` and removes
|
|
352
|
+
* any reference to it without actually closing it.
|
|
353
|
+
*
|
|
354
|
+
* Returns `true` if the given `mediaKeySession` has been found and removed,
|
|
355
|
+
* `false` otherwise.
|
|
356
|
+
*
|
|
357
|
+
* Note that this may create a `MediaKeySession` leakage in the wrong
|
|
358
|
+
* conditions, cases where this method should be called should be very
|
|
359
|
+
* carefully evaluated.
|
|
360
|
+
* @param {MediaKeySession} mediaKeySession
|
|
361
|
+
* @returns {boolean}
|
|
362
|
+
*/
|
|
363
|
+
LoadedSessionsStore.prototype.removeSessionWithoutClosingIt = function (mediaKeySession) {
|
|
364
|
+
assert(mediaKeySession.sessionId === "", "Initialized `MediaKeySession`s should always be properly closed");
|
|
365
|
+
for (var i = this._storage.length - 1; i >= 0; i--) {
|
|
366
|
+
var stored = this._storage[i];
|
|
367
|
+
if (stored.mediaKeySession === mediaKeySession) {
|
|
368
|
+
this._storage.splice(i, 1);
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return false;
|
|
373
|
+
};
|
|
349
374
|
/**
|
|
350
375
|
* Get the index of a stored MediaKeySession entry based on its
|
|
351
376
|
* `KeySessionRecord`.
|
|
@@ -26,7 +26,7 @@ import { IBufferType } from "../../segment_buffers";
|
|
|
26
26
|
* `options` argument, which may retry a segment request when it fails.
|
|
27
27
|
*
|
|
28
28
|
* @param {string} bufferType
|
|
29
|
-
* @param {Object}
|
|
29
|
+
* @param {Object} pipeline
|
|
30
30
|
* @param {Object} callbacks
|
|
31
31
|
* @param {Object} options
|
|
32
32
|
* @returns {Function}
|
|
@@ -34,7 +34,7 @@ var generateRequestID = idGenerator();
|
|
|
34
34
|
* `options` argument, which may retry a segment request when it fails.
|
|
35
35
|
*
|
|
36
36
|
* @param {string} bufferType
|
|
37
|
-
* @param {Object}
|
|
37
|
+
* @param {Object} pipeline
|
|
38
38
|
* @param {Object} callbacks
|
|
39
39
|
* @param {Object} options
|
|
40
40
|
* @returns {Function}
|
|
@@ -17,6 +17,7 @@ import { distinctUntilChanged, ignoreElements, map, merge as observableMerge, sk
|
|
|
17
17
|
import { MediaError } from "../../errors";
|
|
18
18
|
import { fromEvent } from "../../utils/event_emitter";
|
|
19
19
|
import filterMap from "../../utils/filter_map";
|
|
20
|
+
import isNullOrUndefined from "../../utils/is_null_or_undefined";
|
|
20
21
|
import createSharedReference from "../../utils/reference";
|
|
21
22
|
import EVENTS from "./events_generators";
|
|
22
23
|
// NOTE As of now (RxJS 7.4.0), RxJS defines `ignoreElements` default
|
|
@@ -54,7 +55,7 @@ export default function ContentTimeBoundariesObserver(manifest, streams, playbac
|
|
|
54
55
|
"earliest time announced in the Manifest.");
|
|
55
56
|
return EVENTS.warning(warning);
|
|
56
57
|
}
|
|
57
|
-
else if (wantedPosition > maximumPositionCalculator.
|
|
58
|
+
else if (wantedPosition > maximumPositionCalculator.getMaximumAvailablePosition()) {
|
|
58
59
|
var warning = new MediaError("MEDIA_TIME_AFTER_MANIFEST", "The current position is after the latest " +
|
|
59
60
|
"time announced in the Manifest.");
|
|
60
61
|
return EVENTS.warning(warning);
|
|
@@ -68,32 +69,31 @@ export default function ContentTimeBoundariesObserver(manifest, streams, playbac
|
|
|
68
69
|
*/
|
|
69
70
|
var contentDuration = createSharedReference(undefined);
|
|
70
71
|
var updateDurationOnManifestUpdate$ = fromEvent(manifest, "manifestUpdate").pipe(startWith(null), tap(function () {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
else {
|
|
76
|
-
// TODO handle finished dynamic contents?
|
|
77
|
-
contentDuration.setValue(undefined);
|
|
78
|
-
}
|
|
72
|
+
var duration = manifest.isDynamic ?
|
|
73
|
+
maximumPositionCalculator.getEndingPosition() :
|
|
74
|
+
maximumPositionCalculator.getMaximumAvailablePosition();
|
|
75
|
+
contentDuration.setValue(duration);
|
|
79
76
|
}), ignoreElements());
|
|
80
77
|
var updateDurationAndTimeBoundsOnTrackChange$ = streams.pipe(tap(function (message) {
|
|
81
78
|
if (message.type === "adaptationChange") {
|
|
79
|
+
if (!manifest.isLastPeriodKnown) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
82
|
var lastPeriod = manifest.periods[manifest.periods.length - 1];
|
|
83
83
|
if (message.value.period.id === (lastPeriod === null || lastPeriod === void 0 ? void 0 : lastPeriod.id)) {
|
|
84
|
-
if (message.value.type === "audio") {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
contentDuration.setValue(maximumPositionCalculator.getCurrentMaximumPosition());
|
|
84
|
+
if (message.value.type === "audio" || message.value.type === "video") {
|
|
85
|
+
if (message.value.type === "audio") {
|
|
86
|
+
maximumPositionCalculator
|
|
87
|
+
.updateLastAudioAdaptation(message.value.adaptation);
|
|
89
88
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
.updateLastVideoAdaptation(message.value.adaptation);
|
|
94
|
-
if (!manifest.isDynamic) {
|
|
95
|
-
contentDuration.setValue(maximumPositionCalculator.getCurrentMaximumPosition());
|
|
89
|
+
else {
|
|
90
|
+
maximumPositionCalculator
|
|
91
|
+
.updateLastVideoAdaptation(message.value.adaptation);
|
|
96
92
|
}
|
|
93
|
+
var newDuration = manifest.isDynamic ?
|
|
94
|
+
maximumPositionCalculator.getMaximumAvailablePosition() :
|
|
95
|
+
maximumPositionCalculator.getEndingPosition();
|
|
96
|
+
contentDuration.setValue(newDuration);
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
}
|
|
@@ -119,7 +119,7 @@ var MaximumPositionCalculator = /** @class */ (function () {
|
|
|
119
119
|
* If no Adaptation has been set, it should be set to `null`.
|
|
120
120
|
*
|
|
121
121
|
* Allows to calculate the maximum position more precizely in
|
|
122
|
-
* `
|
|
122
|
+
* `getMaximumAvailablePosition` and `getEndingPosition`.
|
|
123
123
|
* @param {Object|null} adaptation
|
|
124
124
|
*/
|
|
125
125
|
MaximumPositionCalculator.prototype.updateLastAudioAdaptation = function (adaptation) {
|
|
@@ -130,18 +130,18 @@ var MaximumPositionCalculator = /** @class */ (function () {
|
|
|
130
130
|
* If no Adaptation has been set, it should be set to `null`.
|
|
131
131
|
*
|
|
132
132
|
* Allows to calculate the maximum position more precizely in
|
|
133
|
-
* `
|
|
133
|
+
* `getMaximumAvailablePosition` and `getEndingPosition`.
|
|
134
134
|
* @param {Object|null} adaptation
|
|
135
135
|
*/
|
|
136
136
|
MaximumPositionCalculator.prototype.updateLastVideoAdaptation = function (adaptation) {
|
|
137
137
|
this._lastVideoAdaptation = adaptation;
|
|
138
138
|
};
|
|
139
139
|
/**
|
|
140
|
-
* Returns an estimate of the maximum position reachable
|
|
141
|
-
* circumstances.
|
|
140
|
+
* Returns an estimate of the maximum position currently reachable (i.e.
|
|
141
|
+
* segments are available) under the current circumstances.
|
|
142
142
|
* @returns {number}
|
|
143
143
|
*/
|
|
144
|
-
MaximumPositionCalculator.prototype.
|
|
144
|
+
MaximumPositionCalculator.prototype.getMaximumAvailablePosition = function () {
|
|
145
145
|
var _a;
|
|
146
146
|
if (this._manifest.isDynamic) {
|
|
147
147
|
return (_a = this._manifest.getLivePosition()) !== null && _a !== void 0 ? _a : this._manifest.getMaximumSafePosition();
|
|
@@ -155,7 +155,7 @@ var MaximumPositionCalculator = /** @class */ (function () {
|
|
|
155
155
|
return this._manifest.getMaximumSafePosition();
|
|
156
156
|
}
|
|
157
157
|
else {
|
|
158
|
-
var lastVideoPosition =
|
|
158
|
+
var lastVideoPosition = getLastAvailablePositionFromAdaptation(this._lastVideoAdaptation);
|
|
159
159
|
if (typeof lastVideoPosition !== "number") {
|
|
160
160
|
return this._manifest.getMaximumSafePosition();
|
|
161
161
|
}
|
|
@@ -163,15 +163,15 @@ var MaximumPositionCalculator = /** @class */ (function () {
|
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
else if (this._lastVideoAdaptation === null) {
|
|
166
|
-
var lastAudioPosition =
|
|
166
|
+
var lastAudioPosition = getLastAvailablePositionFromAdaptation(this._lastAudioAdaptation);
|
|
167
167
|
if (typeof lastAudioPosition !== "number") {
|
|
168
168
|
return this._manifest.getMaximumSafePosition();
|
|
169
169
|
}
|
|
170
170
|
return lastAudioPosition;
|
|
171
171
|
}
|
|
172
172
|
else {
|
|
173
|
-
var lastAudioPosition =
|
|
174
|
-
var lastVideoPosition =
|
|
173
|
+
var lastAudioPosition = getLastAvailablePositionFromAdaptation(this._lastAudioAdaptation);
|
|
174
|
+
var lastVideoPosition = getLastAvailablePositionFromAdaptation(this._lastVideoAdaptation);
|
|
175
175
|
if (typeof lastAudioPosition !== "number" ||
|
|
176
176
|
typeof lastVideoPosition !== "number") {
|
|
177
177
|
return this._manifest.getMaximumSafePosition();
|
|
@@ -181,20 +181,58 @@ var MaximumPositionCalculator = /** @class */ (function () {
|
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
183
|
};
|
|
184
|
+
/**
|
|
185
|
+
* Returns an estimate of the actual ending position once
|
|
186
|
+
* the full content is available.
|
|
187
|
+
* Returns `undefined` if that could not be determined, for various reasons.
|
|
188
|
+
* @returns {number|undefined}
|
|
189
|
+
*/
|
|
190
|
+
MaximumPositionCalculator.prototype.getEndingPosition = function () {
|
|
191
|
+
var _a, _b;
|
|
192
|
+
if (!this._manifest.isDynamic) {
|
|
193
|
+
return this.getMaximumAvailablePosition();
|
|
194
|
+
}
|
|
195
|
+
if (this._lastVideoAdaptation === undefined ||
|
|
196
|
+
this._lastAudioAdaptation === undefined) {
|
|
197
|
+
return undefined;
|
|
198
|
+
}
|
|
199
|
+
else if (this._lastAudioAdaptation === null) {
|
|
200
|
+
if (this._lastVideoAdaptation === null) {
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
return (_a = getEndingPositionFromAdaptation(this._lastVideoAdaptation)) !== null && _a !== void 0 ? _a : undefined;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else if (this._lastVideoAdaptation === null) {
|
|
208
|
+
return (_b = getEndingPositionFromAdaptation(this._lastAudioAdaptation)) !== null && _b !== void 0 ? _b : undefined;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
var lastAudioPosition = getEndingPositionFromAdaptation(this._lastAudioAdaptation);
|
|
212
|
+
var lastVideoPosition = getEndingPositionFromAdaptation(this._lastVideoAdaptation);
|
|
213
|
+
if (typeof lastAudioPosition !== "number" ||
|
|
214
|
+
typeof lastVideoPosition !== "number") {
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
return Math.min(lastAudioPosition, lastVideoPosition);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
184
222
|
return MaximumPositionCalculator;
|
|
185
223
|
}());
|
|
186
224
|
/**
|
|
187
|
-
* Returns
|
|
225
|
+
* Returns last currently available position from the Adaptation given.
|
|
188
226
|
* `undefined` if a time could not be found.
|
|
189
|
-
*
|
|
227
|
+
* `null` if the Adaptation has no segments (it could be that it didn't started or
|
|
190
228
|
* that it already finished for example).
|
|
191
229
|
*
|
|
192
|
-
* We consider the earliest last
|
|
193
|
-
*
|
|
230
|
+
* We consider the earliest last available position from every Representation
|
|
231
|
+
* in the given Adaptation.
|
|
194
232
|
* @param {Object} adaptation
|
|
195
233
|
* @returns {Number|undefined|null}
|
|
196
234
|
*/
|
|
197
|
-
function
|
|
235
|
+
function getLastAvailablePositionFromAdaptation(adaptation) {
|
|
198
236
|
var representations = adaptation.representations;
|
|
199
237
|
var min = null;
|
|
200
238
|
/**
|
|
@@ -207,18 +245,52 @@ function getLastPositionFromAdaptation(adaptation) {
|
|
|
207
245
|
for (var i = 0; i < representations.length; i++) {
|
|
208
246
|
if (representations[i].index !== lastIndex) {
|
|
209
247
|
lastIndex = representations[i].index;
|
|
210
|
-
var lastPosition = representations[i].index.
|
|
248
|
+
var lastPosition = representations[i].index.getLastAvailablePosition();
|
|
211
249
|
if (lastPosition === undefined) { // we cannot tell
|
|
212
250
|
return undefined;
|
|
213
251
|
}
|
|
214
252
|
if (lastPosition !== null) {
|
|
215
|
-
min = min
|
|
253
|
+
min = isNullOrUndefined(min) ? lastPosition :
|
|
216
254
|
Math.min(min, lastPosition);
|
|
217
255
|
}
|
|
218
256
|
}
|
|
219
257
|
}
|
|
220
|
-
|
|
221
|
-
|
|
258
|
+
return min;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Returns ending time from the Adaptation given, once all its segments are
|
|
262
|
+
* available.
|
|
263
|
+
* `undefined` if a time could not be found.
|
|
264
|
+
* `null` if the Adaptation has no segments (it could be that it already
|
|
265
|
+
* finished for example).
|
|
266
|
+
*
|
|
267
|
+
* We consider the earliest ending time from every Representation in the given
|
|
268
|
+
* Adaptation.
|
|
269
|
+
* @param {Object} adaptation
|
|
270
|
+
* @returns {Number|undefined|null}
|
|
271
|
+
*/
|
|
272
|
+
function getEndingPositionFromAdaptation(adaptation) {
|
|
273
|
+
var representations = adaptation.representations;
|
|
274
|
+
var min = null;
|
|
275
|
+
/**
|
|
276
|
+
* Some Manifest parsers use the exact same `IRepresentationIndex` reference
|
|
277
|
+
* for each Representation of a given Adaptation, because in the actual source
|
|
278
|
+
* Manifest file, indexing data is often defined at Adaptation-level.
|
|
279
|
+
* This variable allows to optimize the logic here when this is the case.
|
|
280
|
+
*/
|
|
281
|
+
var lastIndex;
|
|
282
|
+
for (var i = 0; i < representations.length; i++) {
|
|
283
|
+
if (representations[i].index !== lastIndex) {
|
|
284
|
+
lastIndex = representations[i].index;
|
|
285
|
+
var lastPosition = representations[i].index.getEnd();
|
|
286
|
+
if (lastPosition === undefined) { // we cannot tell
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
if (lastPosition !== null) {
|
|
290
|
+
min = isNullOrUndefined(min) ? lastPosition :
|
|
291
|
+
Math.min(min, lastPosition);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
222
294
|
}
|
|
223
295
|
return min;
|
|
224
296
|
}
|
|
@@ -75,23 +75,35 @@ export default function checkForDiscontinuity(content, checkedRange, nextSegment
|
|
|
75
75
|
// and no segment will fill in that hole
|
|
76
76
|
(nextSegmentStart === null ||
|
|
77
77
|
nextBufferedSegment.infos.segment.end <= nextSegmentStart)) {
|
|
78
|
+
var discontinuityEnd = nextBufferedSegment.bufferedStart;
|
|
79
|
+
if (!hasFinishedLoading &&
|
|
80
|
+
representation.index.awaitSegmentBetween(checkedRange.start, discontinuityEnd) !== false) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
78
83
|
log.debug("RS: current discontinuity encountered", adaptation.type, nextBufferedSegment.bufferedStart);
|
|
79
84
|
return { start: undefined,
|
|
80
|
-
end:
|
|
85
|
+
end: discontinuityEnd };
|
|
81
86
|
}
|
|
82
87
|
// Check if there's a discontinuity BETWEEN segments of the current range
|
|
83
88
|
var nextHoleIdx = getIndexOfFirstDiscontinuityBetweenChunks(bufferedSegments, checkedRange, nextBufferedInRangeIdx + 1);
|
|
84
89
|
// If there was a hole between two consecutives segments, and if this hole
|
|
85
90
|
// comes before the next segment to load, there is a discontinuity (that hole!)
|
|
86
|
-
if (nextHoleIdx !== null
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
if (nextHoleIdx !== null) {
|
|
92
|
+
var segmentInfoBeforeHole = bufferedSegments[nextHoleIdx - 1];
|
|
93
|
+
var segmentInfoAfterHole = bufferedSegments[nextHoleIdx];
|
|
94
|
+
if (nextSegmentStart === null ||
|
|
95
|
+
segmentInfoAfterHole.infos.segment.end <= nextSegmentStart) {
|
|
96
|
+
if (!hasFinishedLoading && representation.index
|
|
97
|
+
.awaitSegmentBetween(segmentInfoBeforeHole.infos.segment.end, segmentInfoAfterHole.infos.segment.time) !== false) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
var start = segmentInfoBeforeHole.bufferedEnd;
|
|
101
|
+
var end = segmentInfoAfterHole.bufferedStart;
|
|
102
|
+
log.debug("RS: future discontinuity encountered", adaptation.type, start, end);
|
|
103
|
+
return { start: start, end: end };
|
|
104
|
+
}
|
|
93
105
|
}
|
|
94
|
-
|
|
106
|
+
if (nextSegmentStart === null) {
|
|
95
107
|
// If no hole between segments and no segment to load, check for a
|
|
96
108
|
// discontinuity at the end of the Period
|
|
97
109
|
if (hasFinishedLoading && period.end !== undefined) { // Period is finished
|