rx-player 3.27.0-dev.20220317 → 3.27.0-dev.2022032800
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/.eslintrc.js +0 -4
- package/CHANGELOG.md +5 -2
- package/VERSION +1 -1
- package/dist/_esm5.processed/compat/eme/close_session.js +1 -2
- package/dist/_esm5.processed/compat/eme/custom_key_system_access.d.ts +15 -0
- package/dist/_esm5.processed/compat/eme/custom_key_system_access.js +1 -17
- package/dist/_esm5.processed/compat/eme/custom_media_keys/ie11_media_keys.js +6 -7
- package/dist/_esm5.processed/compat/eme/custom_media_keys/index.js +3 -4
- package/dist/_esm5.processed/compat/eme/custom_media_keys/old_webkit_media_keys.js +20 -17
- package/dist/_esm5.processed/compat/eme/custom_media_keys/webkit_media_keys.js +29 -14
- package/dist/_esm5.processed/compat/eme/generate_key_request.d.ts +4 -6
- package/dist/_esm5.processed/compat/eme/generate_key_request.js +4 -6
- package/dist/_esm5.processed/compat/eme/load_session.js +1 -2
- package/dist/_esm5.processed/config.d.ts +0 -3
- package/dist/_esm5.processed/core/api/option_utils.d.ts +3 -2
- package/dist/_esm5.processed/core/api/option_utils.js +2 -1
- package/dist/_esm5.processed/core/api/public_api.js +3 -4
- package/dist/_esm5.processed/core/decrypt/attach_media_keys.js +1 -2
- package/dist/_esm5.processed/core/decrypt/clear_on_stop.js +1 -2
- package/dist/_esm5.processed/core/decrypt/content_decryptor.js +12 -5
- package/dist/_esm5.processed/core/decrypt/create_or_load_session.js +1 -1
- package/dist/_esm5.processed/core/decrypt/create_session.d.ts +3 -1
- package/dist/_esm5.processed/core/decrypt/create_session.js +16 -7
- package/dist/_esm5.processed/core/decrypt/find_key_system.js +1 -2
- package/dist/_esm5.processed/core/decrypt/utils/clean_old_loaded_sessions.js +1 -2
- package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.d.ts +94 -1
- package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.js +238 -98
- package/dist/_esm5.processed/core/fetchers/manifest/manifest_fetcher.js +1 -3
- package/dist/_esm5.processed/core/fetchers/utils/try_urls_with_backoff.js +2 -3
- package/dist/_esm5.processed/core/init/initialize_media_source.d.ts +2 -1
- package/dist/_esm5.processed/core/stream/index.d.ts +1 -0
- package/dist/_esm5.processed/core/stream/period/get_adaptation_switch_strategy.d.ts +15 -11
- package/dist/_esm5.processed/core/stream/period/get_adaptation_switch_strategy.js +5 -2
- package/dist/_esm5.processed/core/stream/period/index.d.ts +1 -0
- package/dist/_esm5.processed/core/stream/period/period_stream.d.ts +3 -11
- package/dist/_esm5.processed/core/stream/representation/append_segment_to_buffer.js +4 -3
- package/dist/_esm5.processed/default_config.d.ts +0 -27
- package/dist/_esm5.processed/default_config.js +0 -27
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/thumbnail_loader.js +5 -6
- package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/api/index.js +2 -3
- package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/api/probeMediaConfiguration.d.ts +15 -0
- package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/api/probeMediaConfiguration.js +1 -2
- package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/probers/DRMInfos.js +2 -3
- package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/probers/HDCPPolicy.js +2 -3
- package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/probers/decodingInfo.js +1 -2
- package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/probers/mediaContentType.js +1 -2
- package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/probers/mediaContentTypeWithFeatures/index.js +1 -2
- package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/probers/mediaDisplayInfos.js +1 -2
- package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.js +4 -5
- package/dist/_esm5.processed/public_types.d.ts +1 -0
- package/dist/_esm5.processed/transports/dash/add_segment_integrity_checks_to_loader.js +1 -2
- package/dist/_esm5.processed/transports/dash/image_pipelines.d.ts +4 -3
- package/dist/_esm5.processed/transports/dash/image_pipelines.js +57 -11
- package/dist/_esm5.processed/transports/dash/init_segment_loader.js +1 -2
- package/dist/_esm5.processed/transports/dash/manifest_parser.js +2 -3
- package/dist/_esm5.processed/transports/dash/segment_loader.d.ts +1 -1
- package/dist/_esm5.processed/transports/dash/segment_loader.js +3 -4
- package/dist/_esm5.processed/transports/dash/text_loader.js +1 -2
- package/dist/_esm5.processed/transports/local/segment_loader.js +2 -3
- package/dist/_esm5.processed/transports/metaplaylist/pipelines.js +2 -3
- package/dist/_esm5.processed/transports/smooth/pipelines.js +3 -4
- package/dist/_esm5.processed/transports/smooth/segment_loader.js +3 -4
- package/dist/_esm5.processed/transports/utils/call_custom_manifest_loader.js +1 -2
- package/dist/_esm5.processed/utils/cancellable_sleep.js +1 -2
- package/dist/_esm5.processed/utils/cast_to_observable.js +1 -3
- package/dist/_esm5.processed/utils/request/xhr.js +1 -2
- package/dist/rx-player.js +851 -937
- package/dist/rx-player.min.js +1 -1
- package/package.json +1 -2
- package/scripts/update-version +2 -2
- package/sonar-project.properties +1 -1
- package/src/compat/__tests__/play.test.ts +2 -4
- package/src/compat/eme/close_session.ts +1 -2
- package/src/compat/eme/custom_key_system_access.ts +1 -2
- package/src/compat/eme/custom_media_keys/ie11_media_keys.ts +6 -7
- package/src/compat/eme/custom_media_keys/index.ts +3 -4
- package/src/compat/eme/custom_media_keys/old_webkit_media_keys.ts +21 -18
- package/src/compat/eme/custom_media_keys/webkit_media_keys.ts +28 -16
- package/src/compat/eme/generate_key_request.ts +4 -6
- package/src/compat/eme/load_session.ts +1 -2
- package/src/core/api/__tests__/option_utils.test.ts +12 -0
- package/src/core/api/option_utils.ts +5 -3
- package/src/core/api/public_api.ts +3 -4
- package/src/core/decrypt/attach_media_keys.ts +1 -2
- package/src/core/decrypt/clear_on_stop.ts +1 -2
- package/src/core/decrypt/content_decryptor.ts +16 -6
- package/src/core/decrypt/create_or_load_session.ts +4 -1
- package/src/core/decrypt/create_session.ts +25 -12
- package/src/core/decrypt/find_key_system.ts +1 -2
- package/src/core/decrypt/utils/clean_old_loaded_sessions.ts +1 -2
- package/src/core/decrypt/utils/loaded_sessions_store.ts +256 -105
- package/src/core/fetchers/manifest/manifest_fetcher.ts +1 -3
- package/src/core/fetchers/utils/try_urls_with_backoff.ts +2 -3
- package/src/core/init/initialize_media_source.ts +2 -1
- package/src/core/stream/index.ts +1 -0
- package/src/core/stream/period/get_adaptation_switch_strategy.ts +24 -14
- package/src/core/stream/period/index.ts +1 -0
- package/src/core/stream/period/period_stream.ts +5 -14
- package/src/core/stream/representation/append_segment_to_buffer.ts +17 -13
- package/src/default_config.ts +0 -30
- package/src/experimental/tools/VideoThumbnailLoader/thumbnail_loader.ts +5 -6
- package/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/HDCPPolicy.test.ts +5 -6
- package/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/decodingInfos.test.ts +2 -4
- package/src/experimental/tools/mediaCapabilitiesProber/api/index.ts +2 -3
- package/src/experimental/tools/mediaCapabilitiesProber/api/probeMediaConfiguration.ts +1 -2
- package/src/experimental/tools/mediaCapabilitiesProber/probers/DRMInfos.ts +2 -3
- package/src/experimental/tools/mediaCapabilitiesProber/probers/HDCPPolicy.ts +2 -3
- package/src/experimental/tools/mediaCapabilitiesProber/probers/decodingInfo.ts +1 -2
- package/src/experimental/tools/mediaCapabilitiesProber/probers/mediaContentType.ts +1 -2
- package/src/experimental/tools/mediaCapabilitiesProber/probers/mediaContentTypeWithFeatures/index.ts +1 -2
- package/src/experimental/tools/mediaCapabilitiesProber/probers/mediaDisplayInfos.ts +1 -2
- package/src/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.ts +4 -5
- package/src/public_types.ts +1 -0
- package/src/transports/dash/add_segment_integrity_checks_to_loader.ts +1 -2
- package/src/transports/dash/image_pipelines.ts +12 -14
- package/src/transports/dash/init_segment_loader.ts +1 -2
- package/src/transports/dash/manifest_parser.ts +2 -3
- package/src/transports/dash/segment_loader.ts +4 -5
- package/src/transports/dash/text_loader.ts +2 -3
- package/src/transports/local/segment_loader.ts +2 -3
- package/src/transports/metaplaylist/pipelines.ts +2 -3
- package/src/transports/smooth/pipelines.ts +4 -5
- package/src/transports/smooth/segment_loader.ts +5 -6
- package/src/transports/utils/call_custom_manifest_loader.ts +1 -2
- package/src/utils/cancellable_sleep.ts +1 -2
- package/src/utils/cast_to_observable.ts +0 -2
- package/src/utils/request/xhr.ts +1 -2
- package/tsconfig.json +0 -1
- package/tsconfig.modules.json +0 -1
- package/dist/_esm5.processed/utils/promise.d.ts +0 -17
- package/dist/_esm5.processed/utils/promise.js +0 -18
- package/src/typings/pinkie.d.ts +0 -19
- package/src/utils/__tests__/promise.test.ts +0 -23
- package/src/utils/promise.ts +0 -20
|
@@ -14,12 +14,9 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import
|
|
18
|
-
import {
|
|
19
|
-
ICustomMediaKeySession,
|
|
20
|
-
loadSession,
|
|
21
|
-
} from "../../compat";
|
|
17
|
+
import { ICustomMediaKeySession } from "../../compat";
|
|
22
18
|
import log from "../../log";
|
|
19
|
+
import { CancellationSignal } from "../../utils/task_canceller";
|
|
23
20
|
import {
|
|
24
21
|
IProcessedProtectionData,
|
|
25
22
|
IMediaKeySessionStores,
|
|
@@ -43,12 +40,14 @@ import PersistentSessionsStore from "./utils/persistent_sessions_store";
|
|
|
43
40
|
* @param {Object} stores
|
|
44
41
|
* @param {Object} initData
|
|
45
42
|
* @param {string} wantedSessionType
|
|
43
|
+
* @param {Object} cancelSignal
|
|
46
44
|
* @returns {Promise}
|
|
47
45
|
*/
|
|
48
46
|
export default function createSession(
|
|
49
47
|
stores : IMediaKeySessionStores,
|
|
50
48
|
initData : IProcessedProtectionData,
|
|
51
|
-
wantedSessionType : MediaKeySessionType
|
|
49
|
+
wantedSessionType : MediaKeySessionType,
|
|
50
|
+
cancelSignal : CancellationSignal
|
|
52
51
|
) : Promise<ICreateSessionEvent> {
|
|
53
52
|
const { loadedSessionsStore,
|
|
54
53
|
persistentSessionsStore } = stores;
|
|
@@ -62,7 +61,8 @@ export default function createSession(
|
|
|
62
61
|
}
|
|
63
62
|
return createAndTryToRetrievePersistentSession(loadedSessionsStore,
|
|
64
63
|
persistentSessionsStore,
|
|
65
|
-
initData
|
|
64
|
+
initData,
|
|
65
|
+
cancelSignal);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/**
|
|
@@ -78,8 +78,8 @@ function createTemporarySession(
|
|
|
78
78
|
) : Promise<INewSessionCreatedEvent> {
|
|
79
79
|
log.info("DRM: Creating a new temporary session");
|
|
80
80
|
const entry = loadedSessionsStore.createSession(initData, "temporary");
|
|
81
|
-
return
|
|
82
|
-
|
|
81
|
+
return Promise.resolve({ type: MediaKeySessionLoadingType.Created,
|
|
82
|
+
value: entry });
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/**
|
|
@@ -88,13 +88,18 @@ function createTemporarySession(
|
|
|
88
88
|
* @param {Object} loadedSessionsStore
|
|
89
89
|
* @param {Object} persistentSessionsStore
|
|
90
90
|
* @param {Object} initData
|
|
91
|
+
* @param {Object} cancelSignal
|
|
91
92
|
* @returns {Promise}
|
|
92
93
|
*/
|
|
93
94
|
async function createAndTryToRetrievePersistentSession(
|
|
94
95
|
loadedSessionsStore : LoadedSessionsStore,
|
|
95
96
|
persistentSessionsStore : PersistentSessionsStore,
|
|
96
|
-
initData : IProcessedProtectionData
|
|
97
|
+
initData : IProcessedProtectionData,
|
|
98
|
+
cancelSignal : CancellationSignal
|
|
97
99
|
) : Promise<INewSessionCreatedEvent | IPersistentSessionRecoveryEvent> {
|
|
100
|
+
if (cancelSignal.cancellationError !== null) {
|
|
101
|
+
throw cancelSignal.cancellationError;
|
|
102
|
+
}
|
|
98
103
|
log.info("DRM: Creating persistent MediaKeySession");
|
|
99
104
|
|
|
100
105
|
const entry = loadedSessionsStore.createSession(initData, "persistent-license");
|
|
@@ -105,8 +110,10 @@ async function createAndTryToRetrievePersistentSession(
|
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
try {
|
|
108
|
-
const hasLoadedSession = await
|
|
109
|
-
|
|
113
|
+
const hasLoadedSession = await loadedSessionsStore.loadPersistentSession(
|
|
114
|
+
entry.mediaKeySession,
|
|
115
|
+
storedEntry.sessionId
|
|
116
|
+
);
|
|
110
117
|
if (!hasLoadedSession) {
|
|
111
118
|
log.warn("DRM: No data stored for the loaded session");
|
|
112
119
|
persistentSessionsStore.delete(storedEntry.sessionId);
|
|
@@ -137,6 +144,9 @@ async function createAndTryToRetrievePersistentSession(
|
|
|
137
144
|
* @returns {Observable}
|
|
138
145
|
*/
|
|
139
146
|
async function recreatePersistentSession() : Promise<INewSessionCreatedEvent> {
|
|
147
|
+
if (cancelSignal.cancellationError !== null) {
|
|
148
|
+
throw cancelSignal.cancellationError;
|
|
149
|
+
}
|
|
140
150
|
log.info("DRM: Removing previous persistent session.");
|
|
141
151
|
const persistentEntry = persistentSessionsStore.get(initData);
|
|
142
152
|
if (persistentEntry !== null) {
|
|
@@ -144,6 +154,9 @@ async function createAndTryToRetrievePersistentSession(
|
|
|
144
154
|
}
|
|
145
155
|
|
|
146
156
|
await loadedSessionsStore.closeSession(entry.mediaKeySession);
|
|
157
|
+
if (cancelSignal.cancellationError !== null) {
|
|
158
|
+
throw cancelSignal.cancellationError;
|
|
159
|
+
}
|
|
147
160
|
const newEntry = loadedSessionsStore.createSession(initData,
|
|
148
161
|
"persistent-license");
|
|
149
162
|
return { type: MediaKeySessionLoadingType.Created,
|
|
@@ -24,7 +24,6 @@ import { EncryptedMediaError } from "../../errors";
|
|
|
24
24
|
import log from "../../log";
|
|
25
25
|
import arrayIncludes from "../../utils/array_includes";
|
|
26
26
|
import flatMap from "../../utils/flat_map";
|
|
27
|
-
import PPromise from "../../utils/promise";
|
|
28
27
|
import { CancellationSignal } from "../../utils/task_canceller";
|
|
29
28
|
import { IKeySystemOption } from "./types";
|
|
30
29
|
import MediaKeysInfosStore from "./utils/media_keys_infos_store";
|
|
@@ -258,7 +257,7 @@ export default function getMediaKeySystemAccess(
|
|
|
258
257
|
currentState.keySystemOptions);
|
|
259
258
|
if (cachedKeySystemAccess !== null) {
|
|
260
259
|
log.info("DRM: Found cached compatible keySystem");
|
|
261
|
-
return
|
|
260
|
+
return Promise.resolve({
|
|
262
261
|
type: "reuse-media-key-system-access" as const,
|
|
263
262
|
value: { mediaKeySystemAccess: cachedKeySystemAccess.keySystemAccess,
|
|
264
263
|
options: cachedKeySystemAccess.keySystemOptions },
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import PPromise from "../../../utils/promise";
|
|
18
17
|
import LoadedSessionsStore from "./loaded_sessions_store";
|
|
19
18
|
|
|
20
19
|
/**
|
|
@@ -41,5 +40,5 @@ export default async function cleanOldLoadedSessions(
|
|
|
41
40
|
const entry = entries[i];
|
|
42
41
|
proms.push(loadedSessionsStore.closeSession(entry.mediaKeySession));
|
|
43
42
|
}
|
|
44
|
-
await
|
|
43
|
+
await Promise.all(proms);
|
|
45
44
|
}
|
|
@@ -14,18 +14,13 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import PPromise from "pinkie";
|
|
18
|
-
import { Subscription } from "rxjs";
|
|
19
17
|
import {
|
|
20
18
|
closeSession,
|
|
19
|
+
generateKeyRequest,
|
|
21
20
|
ICustomMediaKeys,
|
|
22
21
|
ICustomMediaKeySession,
|
|
22
|
+
loadSession,
|
|
23
23
|
} from "../../../compat";
|
|
24
|
-
import {
|
|
25
|
-
onKeyMessage$,
|
|
26
|
-
onKeyStatusesChange$,
|
|
27
|
-
} from "../../../compat/event_listeners";
|
|
28
|
-
import config from "../../../config";
|
|
29
24
|
import log from "../../../log";
|
|
30
25
|
import isNullOrUndefined from "../../../utils/is_null_or_undefined";
|
|
31
26
|
import { IProcessedProtectionData } from "../types";
|
|
@@ -58,7 +53,7 @@ export default class LoadedSessionsStore {
|
|
|
58
53
|
|
|
59
54
|
/**
|
|
60
55
|
* Create a new MediaKeySession and store it in this store.
|
|
61
|
-
* @param {Object}
|
|
56
|
+
* @param {Object} initData
|
|
62
57
|
* @param {string} sessionType
|
|
63
58
|
* @returns {Object}
|
|
64
59
|
*/
|
|
@@ -68,7 +63,12 @@ export default class LoadedSessionsStore {
|
|
|
68
63
|
) : IStoredSessionEntry {
|
|
69
64
|
const keySessionRecord = new KeySessionRecord(initData);
|
|
70
65
|
const mediaKeySession = this._mediaKeys.createSession(sessionType);
|
|
71
|
-
const entry = { mediaKeySession,
|
|
66
|
+
const entry = { mediaKeySession,
|
|
67
|
+
sessionType,
|
|
68
|
+
keySessionRecord,
|
|
69
|
+
isGeneratingRequest: false,
|
|
70
|
+
isLoadingPersistentSession: false,
|
|
71
|
+
closingStatus: { type: "none" as const } };
|
|
72
72
|
if (!isNullOrUndefined(mediaKeySession.closed)) {
|
|
73
73
|
mediaKeySession.closed
|
|
74
74
|
.then(() => {
|
|
@@ -86,7 +86,7 @@ export default class LoadedSessionsStore {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
log.debug("DRM-LSS: Add MediaKeySession", entry.sessionType);
|
|
89
|
-
this._storage.push({
|
|
89
|
+
this._storage.push({ ...entry });
|
|
90
90
|
return entry;
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -110,14 +110,145 @@ export default class LoadedSessionsStore {
|
|
|
110
110
|
if (stored.keySessionRecord.isCompatibleWith(initializationData)) {
|
|
111
111
|
this._storage.splice(i, 1);
|
|
112
112
|
this._storage.push(stored);
|
|
113
|
-
return {
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
return { ...stored };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get `LoadedSessionsStore`'s entry for a given MediaKeySession.
|
|
121
|
+
* Returns `null` if the given MediaKeySession is not stored in the
|
|
122
|
+
* `LoadedSessionsStore`.
|
|
123
|
+
* @param {MediaKeySession} mediaKeySession
|
|
124
|
+
* @returns {Object|null}
|
|
125
|
+
*/
|
|
126
|
+
public getEntryForSession(
|
|
127
|
+
mediaKeySession : MediaKeySession | ICustomMediaKeySession
|
|
128
|
+
) : IStoredSessionEntry | null {
|
|
129
|
+
for (let i = this._storage.length - 1; i >= 0; i--) {
|
|
130
|
+
const stored = this._storage[i];
|
|
131
|
+
if (stored.mediaKeySession === mediaKeySession) {
|
|
132
|
+
return { ...stored };
|
|
116
133
|
}
|
|
117
134
|
}
|
|
118
135
|
return null;
|
|
119
136
|
}
|
|
120
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Generate a license request on the given MediaKeySession, while indicating
|
|
140
|
+
* to the LoadedSessionsStore that a license-request is pending so
|
|
141
|
+
* session-closing orders are properly scheduled after it is done.
|
|
142
|
+
* @param {Object} mediaKeySession
|
|
143
|
+
* @param {string} initializationDataType - Initialization data type given
|
|
144
|
+
* e.g. by the "encrypted" event for the corresponding request.
|
|
145
|
+
* @param {Uint8Array} initializationData - Initialization data given e.g. by
|
|
146
|
+
* the "encrypted" event for the corresponding request.
|
|
147
|
+
* @returns {Promise}
|
|
148
|
+
*/
|
|
149
|
+
public async generateLicenseRequest(
|
|
150
|
+
mediaKeySession : MediaKeySession | ICustomMediaKeySession,
|
|
151
|
+
initializationDataType : string | undefined,
|
|
152
|
+
initializationData : Uint8Array
|
|
153
|
+
) : Promise<unknown> {
|
|
154
|
+
let entry : IStoredSessionEntry | undefined;
|
|
155
|
+
for (const stored of this._storage) {
|
|
156
|
+
if (stored.mediaKeySession === mediaKeySession) {
|
|
157
|
+
entry = stored;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (entry === undefined) {
|
|
162
|
+
log.error("DRM-LSS: generateRequest error. No MediaKeySession found with " +
|
|
163
|
+
"the given initData and initDataType");
|
|
164
|
+
return generateKeyRequest(mediaKeySession,
|
|
165
|
+
initializationDataType,
|
|
166
|
+
initializationData);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
entry.isGeneratingRequest = true;
|
|
170
|
+
|
|
171
|
+
// Note the `as string` is needed due to TypeScript not understanding that
|
|
172
|
+
// the `closingStatus` might change in the next checks
|
|
173
|
+
if (entry.closingStatus.type as string !== "none") {
|
|
174
|
+
throw new Error("The `MediaKeySession` is being closed.");
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
await generateKeyRequest(mediaKeySession,
|
|
178
|
+
initializationDataType,
|
|
179
|
+
initializationData);
|
|
180
|
+
} catch (err) {
|
|
181
|
+
if (entry === undefined) {
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
184
|
+
entry.isGeneratingRequest = false;
|
|
185
|
+
if (entry.closingStatus.type === "awaiting") {
|
|
186
|
+
entry.closingStatus.start();
|
|
187
|
+
}
|
|
188
|
+
throw err;
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
if (entry === undefined) {
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
entry.isGeneratingRequest = false;
|
|
195
|
+
if (entry.closingStatus.type === "awaiting") {
|
|
196
|
+
entry.closingStatus.start();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* @param {Object} mediaKeySession
|
|
202
|
+
* @param {string} sessionId
|
|
203
|
+
* @returns {Promise}
|
|
204
|
+
*/
|
|
205
|
+
public async loadPersistentSession(
|
|
206
|
+
mediaKeySession : MediaKeySession | ICustomMediaKeySession,
|
|
207
|
+
sessionId : string
|
|
208
|
+
) : Promise<boolean> {
|
|
209
|
+
let entry : IStoredSessionEntry | undefined;
|
|
210
|
+
for (const stored of this._storage) {
|
|
211
|
+
if (stored.mediaKeySession === mediaKeySession) {
|
|
212
|
+
entry = stored;
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (entry === undefined) {
|
|
217
|
+
log.error("DRM-LSS: loadPersistentSession error. No MediaKeySession found with " +
|
|
218
|
+
"the given initData and initDataType");
|
|
219
|
+
return loadSession(mediaKeySession, sessionId);
|
|
220
|
+
}
|
|
221
|
+
entry.isLoadingPersistentSession = true;
|
|
222
|
+
|
|
223
|
+
// Note the `as string` is needed due to TypeScript not understanding that
|
|
224
|
+
// the `closingStatus` might change in the next checks
|
|
225
|
+
if (entry.closingStatus.type as string !== "none") {
|
|
226
|
+
throw new Error("The `MediaKeySession` is being closed.");
|
|
227
|
+
}
|
|
228
|
+
let ret : boolean;
|
|
229
|
+
try {
|
|
230
|
+
ret = await loadSession(mediaKeySession, sessionId);
|
|
231
|
+
} catch (err) {
|
|
232
|
+
if (entry === undefined) {
|
|
233
|
+
throw err;
|
|
234
|
+
}
|
|
235
|
+
entry.isLoadingPersistentSession = false;
|
|
236
|
+
if (entry.closingStatus.type === "awaiting") {
|
|
237
|
+
entry.closingStatus.start();
|
|
238
|
+
}
|
|
239
|
+
throw err;
|
|
240
|
+
|
|
241
|
+
}
|
|
242
|
+
if (entry === undefined) {
|
|
243
|
+
return ret;
|
|
244
|
+
}
|
|
245
|
+
entry.isLoadingPersistentSession = false;
|
|
246
|
+
if (entry.closingStatus.type === "awaiting") {
|
|
247
|
+
entry.closingStatus.start();
|
|
248
|
+
}
|
|
249
|
+
return ret;
|
|
250
|
+
}
|
|
251
|
+
|
|
121
252
|
/**
|
|
122
253
|
* Close a MediaKeySession and remove its related stored information from the
|
|
123
254
|
* `LoadedSessionsStore`.
|
|
@@ -128,7 +259,7 @@ export default class LoadedSessionsStore {
|
|
|
128
259
|
public async closeSession(
|
|
129
260
|
mediaKeySession : MediaKeySession | ICustomMediaKeySession
|
|
130
261
|
) : Promise<boolean> {
|
|
131
|
-
let entry;
|
|
262
|
+
let entry : IStoredSessionEntry | undefined;
|
|
132
263
|
for (const stored of this._storage) {
|
|
133
264
|
if (stored.mediaKeySession === mediaKeySession) {
|
|
134
265
|
entry = stored;
|
|
@@ -138,10 +269,9 @@ export default class LoadedSessionsStore {
|
|
|
138
269
|
if (entry === undefined) {
|
|
139
270
|
log.warn("DRM-LSS: No MediaKeySession found with " +
|
|
140
271
|
"the given initData and initDataType");
|
|
141
|
-
return
|
|
272
|
+
return Promise.resolve(false);
|
|
142
273
|
}
|
|
143
|
-
|
|
144
|
-
return PPromise.resolve(true);
|
|
274
|
+
return this._closeEntry(entry);
|
|
145
275
|
}
|
|
146
276
|
|
|
147
277
|
/**
|
|
@@ -176,10 +306,17 @@ export default class LoadedSessionsStore {
|
|
|
176
306
|
this._storage = [];
|
|
177
307
|
|
|
178
308
|
const closingProms = allEntries
|
|
179
|
-
.map((entry) =>
|
|
180
|
-
await
|
|
309
|
+
.map((entry) => this._closeEntry(entry));
|
|
310
|
+
await Promise.all(closingProms);
|
|
181
311
|
}
|
|
182
312
|
|
|
313
|
+
/**
|
|
314
|
+
* Get the index of a stored MediaKeySession entry based on its
|
|
315
|
+
* `KeySessionRecord`.
|
|
316
|
+
* Returns -1 if not found.
|
|
317
|
+
* @param {Object} record
|
|
318
|
+
* @returns {number}
|
|
319
|
+
*/
|
|
183
320
|
private getIndex(record : KeySessionRecord) : number {
|
|
184
321
|
for (let i = 0; i < this._storage.length; i++) {
|
|
185
322
|
const stored = this._storage[i];
|
|
@@ -189,6 +326,50 @@ export default class LoadedSessionsStore {
|
|
|
189
326
|
}
|
|
190
327
|
return -1;
|
|
191
328
|
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Prepare the closure of a `MediaKeySession` stored as an entry of the
|
|
332
|
+
* `LoadedSessionsStore`.
|
|
333
|
+
* Allows to postpone the closure action if another MediaKeySession action
|
|
334
|
+
* is already pending.
|
|
335
|
+
* @param {Object} entry
|
|
336
|
+
* @returns {Promise.<boolean>}
|
|
337
|
+
*/
|
|
338
|
+
private async _closeEntry(
|
|
339
|
+
entry : IStoredSessionEntry
|
|
340
|
+
) : Promise<boolean> {
|
|
341
|
+
const { mediaKeySession } = entry;
|
|
342
|
+
return new Promise((resolve, reject) => {
|
|
343
|
+
if (entry !== undefined &&
|
|
344
|
+
(
|
|
345
|
+
entry.isLoadingPersistentSession || entry.isGeneratingRequest
|
|
346
|
+
))
|
|
347
|
+
{
|
|
348
|
+
entry.closingStatus = { type: "awaiting",
|
|
349
|
+
start: tryClosingEntryAndResolve };
|
|
350
|
+
} else {
|
|
351
|
+
tryClosingEntryAndResolve();
|
|
352
|
+
}
|
|
353
|
+
function tryClosingEntryAndResolve() {
|
|
354
|
+
if (entry !== undefined) {
|
|
355
|
+
entry.closingStatus = { type: "pending" };
|
|
356
|
+
}
|
|
357
|
+
safelyCloseMediaKeySession(mediaKeySession)
|
|
358
|
+
.then(() => {
|
|
359
|
+
if (entry !== undefined) {
|
|
360
|
+
entry.closingStatus = { type: "done" };
|
|
361
|
+
}
|
|
362
|
+
resolve(true);
|
|
363
|
+
})
|
|
364
|
+
.catch((err) => {
|
|
365
|
+
if (entry !== undefined) {
|
|
366
|
+
entry.closingStatus = { type: "failed" };
|
|
367
|
+
}
|
|
368
|
+
reject(err);
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
}
|
|
192
373
|
}
|
|
193
374
|
|
|
194
375
|
/** Information linked to a `MediaKeySession` created by the `LoadedSessionsStore`. */
|
|
@@ -217,102 +398,72 @@ export interface IStoredSessionEntry {
|
|
|
217
398
|
* which the MediaKeySession was created.
|
|
218
399
|
*/
|
|
219
400
|
sessionType : MediaKeySessionType;
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Set to `true` while a `generateRequest` call is pending.
|
|
404
|
+
* This information might be useful as it is one of the operation we have to
|
|
405
|
+
* wait for before closing a MediaKeySession.
|
|
406
|
+
*/
|
|
407
|
+
isGeneratingRequest : boolean;
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Set to `true` while a `load` call is pending.
|
|
411
|
+
* This information might be useful as it is one of the operation we have to
|
|
412
|
+
* wait for before closing a MediaKeySession.
|
|
413
|
+
*/
|
|
414
|
+
isLoadingPersistentSession : boolean;
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* The status of a potential `MediaKeySession`'s close request.
|
|
418
|
+
* Closing a MediaKeySession could be made complex as it normally cannot
|
|
419
|
+
* happen until `generateRequest` or `load` has been called.
|
|
420
|
+
*
|
|
421
|
+
* To avoid problems while still staying compatible to the most devices
|
|
422
|
+
* possible - which may have strange implementation of the specification -
|
|
423
|
+
* we're adding the `closingStatus` property allowing to perform multiple
|
|
424
|
+
* type of interaction while a close operation is either pending or is
|
|
425
|
+
* awaited.
|
|
426
|
+
*/
|
|
427
|
+
closingStatus :
|
|
428
|
+
/** Status when the MediaKeySession is currently being closed. */
|
|
429
|
+
{ type : "pending" } |
|
|
430
|
+
/** Status when the MediaKeySession has been closed. */
|
|
431
|
+
{ type : "done" } |
|
|
432
|
+
/** Status when the MediaKeySession failed to close. */
|
|
433
|
+
{ type : "failed" } |
|
|
434
|
+
/**
|
|
435
|
+
* Status when a close order has been received for this MediaKeySession
|
|
436
|
+
* while some sensitive operation (examples are `generateRequest` and `load`
|
|
437
|
+
* calls).
|
|
438
|
+
* The `LoadedSessionsStore` should call `start` once it has finished those
|
|
439
|
+
* operations.
|
|
440
|
+
*/
|
|
441
|
+
{
|
|
442
|
+
type : "awaiting";
|
|
443
|
+
start : () => void;
|
|
444
|
+
} |
|
|
445
|
+
/** Status when the MediaKeySession failed to close. */
|
|
446
|
+
{ type : "none" };
|
|
220
447
|
}
|
|
221
448
|
|
|
222
449
|
/**
|
|
223
|
-
* Close a MediaKeySession
|
|
224
|
-
* this action throws an error.
|
|
450
|
+
* Close a MediaKeySession and just log an error if it fails (while resolving).
|
|
225
451
|
* Emits then complete when done.
|
|
226
452
|
* @param {MediaKeySession} mediaKeySession
|
|
227
453
|
* @returns {Observable}
|
|
228
454
|
*/
|
|
229
|
-
function safelyCloseMediaKeySession(
|
|
455
|
+
async function safelyCloseMediaKeySession(
|
|
230
456
|
mediaKeySession : MediaKeySession | ICustomMediaKeySession
|
|
231
|
-
) : Promise<
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
* events, whichever comes first.
|
|
239
|
-
* Emits then complete when done.
|
|
240
|
-
* @param {number} retryNb - The attempt number starting at 0.
|
|
241
|
-
* @returns {Observable}
|
|
242
|
-
*/
|
|
243
|
-
async function recursivelyTryToCloseMediaKeySession(
|
|
244
|
-
retryNb : number
|
|
245
|
-
) : Promise<unknown> {
|
|
246
|
-
log.debug("DRM: Trying to close a MediaKeySession",
|
|
247
|
-
mediaKeySession.sessionId,
|
|
248
|
-
retryNb);
|
|
249
|
-
try {
|
|
250
|
-
await closeSession(mediaKeySession);
|
|
251
|
-
log.debug("DRM: Succeeded to close MediaKeySession");
|
|
252
|
-
return undefined;
|
|
253
|
-
} catch (err : unknown) {
|
|
254
|
-
// Unitialized MediaKeySession may not close properly until their
|
|
255
|
-
// corresponding `generateRequest` or `load` call are handled by the
|
|
256
|
-
// browser.
|
|
257
|
-
// In that case the EME specification tells us that the browser is
|
|
258
|
-
// supposed to reject the `close` call with an InvalidStateError.
|
|
259
|
-
if (!(err instanceof Error) || err.name !== "InvalidStateError" ||
|
|
260
|
-
mediaKeySession.sessionId !== "")
|
|
261
|
-
{
|
|
262
|
-
return failToCloseSession(err);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const { EME_SESSION_CLOSING_MAX_RETRY,
|
|
266
|
-
EME_SESSION_CLOSING_INITIAL_DELAY,
|
|
267
|
-
EME_SESSION_CLOSING_MAX_DELAY } = config.getCurrent();
|
|
268
|
-
|
|
269
|
-
// We will retry either:
|
|
270
|
-
// - when an event indicates that the MediaKeySession is
|
|
271
|
-
// initialized (`callable` is the proper EME term here)
|
|
272
|
-
// - after a delay, raising exponentially
|
|
273
|
-
const nextRetryNb = retryNb + 1;
|
|
274
|
-
if (nextRetryNb > EME_SESSION_CLOSING_MAX_RETRY) {
|
|
275
|
-
return failToCloseSession(err);
|
|
276
|
-
}
|
|
277
|
-
const delay = Math.min(Math.pow(2, retryNb) * EME_SESSION_CLOSING_INITIAL_DELAY,
|
|
278
|
-
EME_SESSION_CLOSING_MAX_DELAY);
|
|
279
|
-
log.warn("DRM: attempt to close a mediaKeySession failed, " +
|
|
280
|
-
"scheduling retry...", delay);
|
|
281
|
-
|
|
282
|
-
let ksChangeSub : undefined | Subscription;
|
|
283
|
-
const ksChangeProm = new Promise((res) => {
|
|
284
|
-
ksChangeSub = onKeyStatusesChange$(mediaKeySession).subscribe(res);
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
let ksMsgSub : undefined | Subscription;
|
|
288
|
-
const ksMsgProm = new Promise((res) => {
|
|
289
|
-
ksMsgSub = onKeyMessage$(mediaKeySession).subscribe(res);
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
let sleepTimer : undefined | number;
|
|
293
|
-
const sleepProm = new Promise((res) => {
|
|
294
|
-
sleepTimer = window.setTimeout(res, delay);
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
await PPromise.race([ksChangeProm, ksMsgProm, sleepProm]);
|
|
298
|
-
ksChangeSub?.unsubscribe();
|
|
299
|
-
ksMsgSub?.unsubscribe();
|
|
300
|
-
clearTimeout(sleepTimer);
|
|
301
|
-
|
|
302
|
-
return recursivelyTryToCloseMediaKeySession(nextRetryNb);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Log error anouncing that we could not close the MediaKeySession and emits
|
|
308
|
-
* then complete through Observable.
|
|
309
|
-
* TODO Emit warning?
|
|
310
|
-
* @returns {Observable}
|
|
311
|
-
*/
|
|
312
|
-
function failToCloseSession(err : unknown) : Promise<null> {
|
|
457
|
+
) : Promise<void> {
|
|
458
|
+
log.debug("DRM: Trying to close a MediaKeySession", mediaKeySession.sessionId);
|
|
459
|
+
try {
|
|
460
|
+
await closeSession(mediaKeySession);
|
|
461
|
+
log.debug("DRM: Succeeded to close MediaKeySession");
|
|
462
|
+
return ;
|
|
463
|
+
} catch (err : unknown) {
|
|
313
464
|
log.error("DRM: Could not close MediaKeySession: " +
|
|
314
465
|
(err instanceof Error ? err.toString() :
|
|
315
466
|
"Unknown error"));
|
|
316
|
-
return
|
|
467
|
+
return ;
|
|
317
468
|
}
|
|
318
469
|
}
|
|
@@ -30,7 +30,6 @@ import {
|
|
|
30
30
|
ITransportPipelines,
|
|
31
31
|
} from "../../../transports";
|
|
32
32
|
import assert from "../../../utils/assert";
|
|
33
|
-
import PPromise from "../../../utils/promise";
|
|
34
33
|
import TaskCanceller from "../../../utils/task_canceller";
|
|
35
34
|
import errorSelector from "../utils/error_selector";
|
|
36
35
|
import {
|
|
@@ -431,6 +430,5 @@ export default class ManifestFetcher {
|
|
|
431
430
|
* @returns {boolean}
|
|
432
431
|
*/
|
|
433
432
|
function isPromise<T>(val : T | Promise<T>) : val is Promise<T> {
|
|
434
|
-
return val instanceof
|
|
435
|
-
val instanceof Promise;
|
|
433
|
+
return val instanceof Promise;
|
|
436
434
|
}
|
|
@@ -24,7 +24,6 @@ import {
|
|
|
24
24
|
import log from "../../../log";
|
|
25
25
|
import cancellableSleep from "../../../utils/cancellable_sleep";
|
|
26
26
|
import getFuzzedDelay from "../../../utils/get_fuzzed_delay";
|
|
27
|
-
import PPromise from "../../../utils/promise";
|
|
28
27
|
import TaskCanceller, {
|
|
29
28
|
CancellationSignal,
|
|
30
29
|
} from "../../../utils/task_canceller";
|
|
@@ -171,7 +170,7 @@ export function tryURLsWithBackoff<T>(
|
|
|
171
170
|
cancellationSignal : CancellationSignal
|
|
172
171
|
) : Promise<T> {
|
|
173
172
|
if (cancellationSignal.isCancelled) {
|
|
174
|
-
return
|
|
173
|
+
return Promise.reject(cancellationSignal.cancellationError);
|
|
175
174
|
}
|
|
176
175
|
|
|
177
176
|
const { baseDelay,
|
|
@@ -185,7 +184,7 @@ export function tryURLsWithBackoff<T>(
|
|
|
185
184
|
const urlsToTry = urls.slice();
|
|
186
185
|
if (urlsToTry.length === 0) {
|
|
187
186
|
log.warn("Fetchers: no URL given to `tryURLsWithBackoff`.");
|
|
188
|
-
return
|
|
187
|
+
return Promise.reject(new Error("No URL to request"));
|
|
189
188
|
}
|
|
190
189
|
return tryURLsRecursively(urlsToTry[0], 0);
|
|
191
190
|
|
|
@@ -56,6 +56,7 @@ import {
|
|
|
56
56
|
SegmentFetcherCreator,
|
|
57
57
|
} from "../fetchers";
|
|
58
58
|
import { ITextTrackSegmentBufferOptions } from "../segment_buffers";
|
|
59
|
+
import { IAudioTrackSwitchingMode } from "../stream";
|
|
59
60
|
import openMediaSource from "./create_media_source";
|
|
60
61
|
import EVENTS from "./events_generators";
|
|
61
62
|
import getInitialTime, {
|
|
@@ -105,7 +106,7 @@ export interface IInitializeArguments {
|
|
|
105
106
|
*/
|
|
106
107
|
enableFastSwitching : boolean;
|
|
107
108
|
/** Strategy when switching of audio track. */
|
|
108
|
-
audioTrackSwitchingMode :
|
|
109
|
+
audioTrackSwitchingMode : IAudioTrackSwitchingMode;
|
|
109
110
|
/** Behavior when a new video and/or audio codec is encountered. */
|
|
110
111
|
onCodecSwitch : "continue" | "reload";
|
|
111
112
|
};
|
package/src/core/stream/index.ts
CHANGED