rx-player 4.2.0-dev.2024081301 → 4.2.0-dev.2024082600
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/.vscode/settings.json +7 -0
- package/CHANGELOG.md +29 -0
- package/VERSION +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.js +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_worker.js +1 -1
- package/dist/commonjs/compat/eme/custom_media_keys/types.d.ts +3 -0
- package/dist/commonjs/compat/eme/custom_media_keys/types.d.ts.map +1 -1
- package/dist/commonjs/compat/eme/custom_media_keys/webkit_media_keys.d.ts +1 -1
- package/dist/commonjs/compat/eme/custom_media_keys/webkit_media_keys.d.ts.map +1 -1
- package/dist/commonjs/compat/eme/eme-api-implementation.d.ts +2 -2
- package/dist/commonjs/compat/eme/eme-api-implementation.d.ts.map +1 -1
- package/dist/commonjs/compat/eme/eme-api-implementation.js +19 -2
- package/dist/commonjs/compat/eme/get_init_data.d.ts +3 -1
- package/dist/commonjs/compat/eme/get_init_data.d.ts.map +1 -1
- package/dist/commonjs/compat/eme/get_init_data.js +2 -2
- package/dist/commonjs/compat/event_listeners.d.ts +21 -19
- package/dist/commonjs/compat/event_listeners.d.ts.map +1 -1
- package/dist/commonjs/compat/event_listeners.js +0 -11
- package/dist/commonjs/core/segment_sinks/inventory/segment_inventory.js +8 -5
- package/dist/commonjs/core/segment_sinks/segment_buffers_store.d.ts.map +1 -1
- package/dist/commonjs/core/segment_sinks/segment_buffers_store.js +5 -2
- package/dist/commonjs/main_thread/api/public_api.d.ts +22 -10
- package/dist/commonjs/main_thread/api/public_api.d.ts.map +1 -1
- package/dist/commonjs/main_thread/api/public_api.js +68 -28
- package/dist/commonjs/main_thread/decrypt/content_decryptor.d.ts +8 -0
- package/dist/commonjs/main_thread/decrypt/content_decryptor.d.ts.map +1 -1
- package/dist/commonjs/main_thread/decrypt/content_decryptor.js +51 -2
- package/dist/commonjs/main_thread/decrypt/types.d.ts +5 -0
- package/dist/commonjs/main_thread/decrypt/types.d.ts.map +1 -1
- package/dist/commonjs/main_thread/init/media_source_content_initializer.js +3 -3
- package/dist/commonjs/main_thread/tracks_store/tracks_store.d.ts +12 -4
- package/dist/commonjs/main_thread/tracks_store/tracks_store.d.ts.map +1 -1
- package/dist/commonjs/main_thread/tracks_store/tracks_store.js +18 -8
- package/dist/commonjs/manifest/classes/adaptation.d.ts.map +1 -1
- package/dist/commonjs/manifest/classes/adaptation.js +1 -4
- package/dist/commonjs/manifest/classes/representation.js +8 -8
- package/dist/commonjs/manifest/utils.d.ts +4 -3
- package/dist/commonjs/manifest/utils.d.ts.map +1 -1
- package/dist/commonjs/manifest/utils.js +13 -7
- package/dist/commonjs/parsers/manifest/dash/common/content_protection_parser.js +4 -4
- package/dist/commonjs/parsers/manifest/local/parse_local_manifest.js +1 -1
- package/dist/commonjs/parsers/manifest/smooth/create_parser.d.ts.map +1 -1
- package/dist/commonjs/parsers/manifest/smooth/create_parser.js +1 -4
- package/dist/commonjs/parsers/manifest/types.d.ts +1 -6
- package/dist/commonjs/parsers/manifest/types.d.ts.map +1 -1
- package/dist/commonjs/public_types.d.ts +69 -0
- package/dist/commonjs/public_types.d.ts.map +1 -1
- package/dist/commonjs/utils/are_codecs_compatible.d.ts.map +1 -1
- package/dist/commonjs/utils/are_codecs_compatible.js +5 -1
- package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
- package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.js +1 -1
- package/dist/es2017/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
- package/dist/es2017/__GENERATED_CODE/embedded_worker.js +1 -1
- package/dist/es2017/compat/eme/custom_media_keys/types.d.ts +3 -0
- package/dist/es2017/compat/eme/custom_media_keys/types.d.ts.map +1 -1
- package/dist/es2017/compat/eme/custom_media_keys/webkit_media_keys.d.ts +1 -1
- package/dist/es2017/compat/eme/custom_media_keys/webkit_media_keys.d.ts.map +1 -1
- package/dist/es2017/compat/eme/eme-api-implementation.d.ts +2 -2
- package/dist/es2017/compat/eme/eme-api-implementation.d.ts.map +1 -1
- package/dist/es2017/compat/eme/eme-api-implementation.js +19 -2
- package/dist/es2017/compat/eme/get_init_data.d.ts +3 -1
- package/dist/es2017/compat/eme/get_init_data.d.ts.map +1 -1
- package/dist/es2017/compat/eme/get_init_data.js +2 -2
- package/dist/es2017/compat/event_listeners.d.ts +21 -19
- package/dist/es2017/compat/event_listeners.d.ts.map +1 -1
- package/dist/es2017/compat/event_listeners.js +0 -11
- package/dist/es2017/core/segment_sinks/inventory/segment_inventory.js +8 -5
- package/dist/es2017/core/segment_sinks/segment_buffers_store.d.ts.map +1 -1
- package/dist/es2017/core/segment_sinks/segment_buffers_store.js +5 -2
- package/dist/es2017/main_thread/api/public_api.d.ts +22 -10
- package/dist/es2017/main_thread/api/public_api.d.ts.map +1 -1
- package/dist/es2017/main_thread/api/public_api.js +64 -24
- package/dist/es2017/main_thread/decrypt/content_decryptor.d.ts +8 -0
- package/dist/es2017/main_thread/decrypt/content_decryptor.d.ts.map +1 -1
- package/dist/es2017/main_thread/decrypt/content_decryptor.js +47 -2
- package/dist/es2017/main_thread/decrypt/types.d.ts +5 -0
- package/dist/es2017/main_thread/decrypt/types.d.ts.map +1 -1
- package/dist/es2017/main_thread/init/media_source_content_initializer.js +3 -3
- package/dist/es2017/main_thread/tracks_store/tracks_store.d.ts +12 -4
- package/dist/es2017/main_thread/tracks_store/tracks_store.d.ts.map +1 -1
- package/dist/es2017/main_thread/tracks_store/tracks_store.js +18 -8
- package/dist/es2017/manifest/classes/adaptation.d.ts.map +1 -1
- package/dist/es2017/manifest/classes/adaptation.js +1 -1
- package/dist/es2017/manifest/classes/representation.js +8 -8
- package/dist/es2017/manifest/utils.d.ts +4 -3
- package/dist/es2017/manifest/utils.d.ts.map +1 -1
- package/dist/es2017/manifest/utils.js +13 -7
- package/dist/es2017/parsers/manifest/dash/common/content_protection_parser.js +4 -4
- package/dist/es2017/parsers/manifest/local/parse_local_manifest.js +1 -1
- package/dist/es2017/parsers/manifest/smooth/create_parser.d.ts.map +1 -1
- package/dist/es2017/parsers/manifest/smooth/create_parser.js +1 -4
- package/dist/es2017/parsers/manifest/types.d.ts +1 -6
- package/dist/es2017/parsers/manifest/types.d.ts.map +1 -1
- package/dist/es2017/public_types.d.ts +69 -0
- package/dist/es2017/public_types.d.ts.map +1 -1
- package/dist/es2017/utils/are_codecs_compatible.d.ts.map +1 -1
- package/dist/es2017/utils/are_codecs_compatible.js +5 -1
- package/dist/mpd-parser.wasm +0 -0
- package/dist/rx-player.js +18 -18
- package/dist/worker.js +5 -5
- package/package.json +2 -2
- package/src/__GENERATED_CODE/embedded_dash_wasm.ts +1 -1
- package/src/__GENERATED_CODE/embedded_worker.ts +1 -1
- package/src/compat/eme/custom_media_keys/types.ts +4 -0
- package/src/compat/eme/custom_media_keys/webkit_media_keys.ts +1 -1
- package/src/compat/eme/eme-api-implementation.ts +35 -4
- package/src/compat/eme/get_init_data.ts +5 -3
- package/src/compat/event_listeners.ts +30 -5
- package/src/core/segment_sinks/inventory/segment_inventory.ts +7 -4
- package/src/core/segment_sinks/segment_buffers_store.ts +5 -2
- package/src/main_thread/api/public_api.ts +96 -24
- package/src/main_thread/decrypt/content_decryptor.ts +60 -3
- package/src/main_thread/decrypt/types.ts +5 -0
- package/src/main_thread/init/media_source_content_initializer.ts +3 -3
- package/src/main_thread/tracks_store/tracks_store.ts +30 -6
- package/src/manifest/classes/adaptation.ts +1 -3
- package/src/manifest/classes/representation.ts +6 -6
- package/src/manifest/utils.ts +14 -6
- package/src/parsers/manifest/dash/common/content_protection_parser.ts +4 -4
- package/src/parsers/manifest/local/parse_local_manifest.ts +1 -1
- package/src/parsers/manifest/smooth/create_parser.ts +2 -6
- package/src/parsers/manifest/types.ts +1 -7
- package/src/public_types.ts +73 -0
- package/src/utils/are_codecs_compatible.ts +5 -1
- package/vitest.config.mjs +1 -0
|
@@ -30,7 +30,7 @@ import type { IWebKitMediaKeys } from "./webkit_media_keys_constructor";
|
|
|
30
30
|
import { WebKitMediaKeysConstructor } from "./webkit_media_keys_constructor";
|
|
31
31
|
|
|
32
32
|
export interface ICustomWebKitMediaKeys {
|
|
33
|
-
_setVideo: (videoElement: IMediaElement) =>
|
|
33
|
+
_setVideo: (videoElement: IMediaElement) => Promise<unknown>;
|
|
34
34
|
createSession(mimeType: string, initData: Uint8Array): ICustomMediaKeySession;
|
|
35
35
|
setServerCertificate(setServerCertificate: BufferSource): Promise<void>;
|
|
36
36
|
}
|
|
@@ -3,6 +3,7 @@ import assert from "../../utils/assert";
|
|
|
3
3
|
import globalScope from "../../utils/global_scope";
|
|
4
4
|
import isNode from "../../utils/is_node";
|
|
5
5
|
import isNullOrUndefined from "../../utils/is_null_or_undefined";
|
|
6
|
+
import objectAssign from "../../utils/object_assign";
|
|
6
7
|
import type { CancellationSignal } from "../../utils/task_canceller";
|
|
7
8
|
import type { IMediaElement } from "../browser_compatibility_types";
|
|
8
9
|
import { isIE11 } from "../browser_detection";
|
|
@@ -19,7 +20,10 @@ import getMozMediaKeysCallbacks, {
|
|
|
19
20
|
import getOldKitWebKitMediaKeyCallbacks, {
|
|
20
21
|
isOldWebkitMediaElement,
|
|
21
22
|
} from "./custom_media_keys/old_webkit_media_keys";
|
|
22
|
-
import type {
|
|
23
|
+
import type {
|
|
24
|
+
ICustomMediaEncryptedEvent,
|
|
25
|
+
ICustomMediaKeys,
|
|
26
|
+
} from "./custom_media_keys/types";
|
|
23
27
|
import getWebKitMediaKeysCallbacks from "./custom_media_keys/webkit_media_keys";
|
|
24
28
|
import { WebKitMediaKeysConstructor } from "./custom_media_keys/webkit_media_keys_constructor";
|
|
25
29
|
|
|
@@ -63,7 +67,7 @@ export interface IEmeApiImplementation {
|
|
|
63
67
|
*/
|
|
64
68
|
onEncrypted: (
|
|
65
69
|
target: IEventTargetLike,
|
|
66
|
-
listener: (evt:
|
|
70
|
+
listener: (evt: ICustomMediaEncryptedEvent) => void,
|
|
67
71
|
cancelSignal: CancellationSignal,
|
|
68
72
|
) => void;
|
|
69
73
|
|
|
@@ -143,8 +147,8 @@ function getEmeApiImplementation(
|
|
|
143
147
|
let createCustomMediaKeys: (keyType: string) => ICustomMediaKeys;
|
|
144
148
|
|
|
145
149
|
if (preferredApiType === "webkit" && WebKitMediaKeysConstructor !== undefined) {
|
|
146
|
-
onEncrypted = createCompatibleEventListener(["needkey"]);
|
|
147
150
|
const callbacks = getWebKitMediaKeysCallbacks();
|
|
151
|
+
onEncrypted = createOnEncryptedForWebkit();
|
|
148
152
|
isTypeSupported = callbacks.isTypeSupported;
|
|
149
153
|
createCustomMediaKeys = callbacks.createCustomMediaKeys;
|
|
150
154
|
setMediaKeys = callbacks.setMediaKeys;
|
|
@@ -160,7 +164,7 @@ function getEmeApiImplementation(
|
|
|
160
164
|
implementation = "older-webkit";
|
|
161
165
|
// This is for WebKit with prefixed EME api
|
|
162
166
|
} else if (WebKitMediaKeysConstructor !== undefined) {
|
|
163
|
-
onEncrypted =
|
|
167
|
+
onEncrypted = createOnEncryptedForWebkit();
|
|
164
168
|
const callbacks = getWebKitMediaKeysCallbacks();
|
|
165
169
|
isTypeSupported = callbacks.isTypeSupported;
|
|
166
170
|
createCustomMediaKeys = callbacks.createCustomMediaKeys;
|
|
@@ -274,6 +278,33 @@ function getEmeApiImplementation(
|
|
|
274
278
|
implementation,
|
|
275
279
|
};
|
|
276
280
|
}
|
|
281
|
+
/**
|
|
282
|
+
* Create an event listener for the "webkitneedkey" event
|
|
283
|
+
* @returns
|
|
284
|
+
*/
|
|
285
|
+
function createOnEncryptedForWebkit(): IEmeApiImplementation["onEncrypted"] {
|
|
286
|
+
const compatibleEventListener = createCompatibleEventListener(
|
|
287
|
+
["needkey"],
|
|
288
|
+
undefined /* prefixes */,
|
|
289
|
+
);
|
|
290
|
+
const onEncrypted = (
|
|
291
|
+
target: IEventTargetLike,
|
|
292
|
+
listener: (event: ICustomMediaEncryptedEvent) => void,
|
|
293
|
+
cancelSignal: CancellationSignal,
|
|
294
|
+
) => {
|
|
295
|
+
compatibleEventListener(
|
|
296
|
+
target,
|
|
297
|
+
(event?: Event) => {
|
|
298
|
+
const patchedEvent = objectAssign(event as MediaEncryptedEvent, {
|
|
299
|
+
forceSessionRecreation: true,
|
|
300
|
+
});
|
|
301
|
+
listener(patchedEvent);
|
|
302
|
+
},
|
|
303
|
+
cancelSignal,
|
|
304
|
+
);
|
|
305
|
+
};
|
|
306
|
+
return onEncrypted;
|
|
307
|
+
}
|
|
277
308
|
|
|
278
309
|
/**
|
|
279
310
|
* Set the given MediaKeys on the given HTMLMediaElement.
|
|
@@ -20,6 +20,7 @@ import areArraysOfNumbersEqual from "../../utils/are_arrays_of_numbers_equal";
|
|
|
20
20
|
import { be4toi } from "../../utils/byte_parsing";
|
|
21
21
|
import isNullOrUndefined from "../../utils/is_null_or_undefined";
|
|
22
22
|
import { PSSH_TO_INTEGER } from "./constants";
|
|
23
|
+
import type { ICustomMediaEncryptedEvent } from "./custom_media_keys/types";
|
|
23
24
|
|
|
24
25
|
/** Data recuperated from parsing the payload of an `encrypted` event. */
|
|
25
26
|
export interface IEncryptedEventData {
|
|
@@ -50,6 +51,7 @@ export interface IEncryptedEventData {
|
|
|
50
51
|
*/
|
|
51
52
|
data: Uint8Array;
|
|
52
53
|
}>;
|
|
54
|
+
forceSessionRecreation?: boolean | undefined;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
/**
|
|
@@ -145,9 +147,9 @@ function isPSSHAlreadyEncountered(
|
|
|
145
147
|
* encountered in the given event.
|
|
146
148
|
*/
|
|
147
149
|
export default function getInitData(
|
|
148
|
-
encryptedEvent:
|
|
150
|
+
encryptedEvent: ICustomMediaEncryptedEvent,
|
|
149
151
|
): IEncryptedEventData | null {
|
|
150
|
-
const { initData, initDataType } = encryptedEvent;
|
|
152
|
+
const { initData, initDataType, forceSessionRecreation } = encryptedEvent;
|
|
151
153
|
if (isNullOrUndefined(initData)) {
|
|
152
154
|
log.warn("Compat: No init data found on media encrypted event.");
|
|
153
155
|
return null;
|
|
@@ -155,5 +157,5 @@ export default function getInitData(
|
|
|
155
157
|
|
|
156
158
|
const initDataBytes = new Uint8Array(initData);
|
|
157
159
|
const values = getInitializationDataValues(initDataBytes);
|
|
158
|
-
return { type: initDataType, values };
|
|
160
|
+
return { type: initDataType, values, forceSessionRecreation };
|
|
159
161
|
}
|
|
@@ -30,6 +30,7 @@ import type {
|
|
|
30
30
|
IEventTarget,
|
|
31
31
|
IMediaElement,
|
|
32
32
|
} from "./browser_compatibility_types";
|
|
33
|
+
import type { ICustomMediaEncryptedEvent } from "./eme/custom_media_keys/types";
|
|
33
34
|
|
|
34
35
|
const BROWSER_PREFIXES = ["", "webkit", "moz", "ms"];
|
|
35
36
|
|
|
@@ -82,8 +83,14 @@ function eventPrefixed(eventNames: string[], prefixes?: string[]): string[] {
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
export interface IEventEmitterLike {
|
|
85
|
-
addEventListener: (
|
|
86
|
-
|
|
86
|
+
addEventListener: (
|
|
87
|
+
eventName: string,
|
|
88
|
+
handler: EventListenerOrEventListenerObject,
|
|
89
|
+
) => void;
|
|
90
|
+
removeEventListener: (
|
|
91
|
+
eventName: string,
|
|
92
|
+
handler: EventListenerOrEventListenerObject,
|
|
93
|
+
) => void;
|
|
87
94
|
}
|
|
88
95
|
|
|
89
96
|
export type IEventTargetLike = HTMLElement | IEventEmitterLike | IEventEmitter<unknown>;
|
|
@@ -99,12 +106,31 @@ export type IEventTargetLike = HTMLElement | IEventEmitterLike | IEventEmitter<u
|
|
|
99
106
|
* @returns {Function} - Returns function allowing to easily add a callback to
|
|
100
107
|
* be triggered when that event is emitted on a given event target.
|
|
101
108
|
*/
|
|
109
|
+
|
|
110
|
+
function createCompatibleEventListener(
|
|
111
|
+
eventNames: Array<"needkey" | "encrypted">,
|
|
112
|
+
prefixes?: string[],
|
|
113
|
+
): (
|
|
114
|
+
element: IEventTargetLike,
|
|
115
|
+
listener: (event: ICustomMediaEncryptedEvent) => void,
|
|
116
|
+
cancelSignal: CancellationSignal,
|
|
117
|
+
) => void;
|
|
118
|
+
|
|
102
119
|
function createCompatibleEventListener(
|
|
103
120
|
eventNames: string[],
|
|
104
121
|
prefixes?: string[],
|
|
105
122
|
): (
|
|
106
123
|
element: IEventTargetLike,
|
|
107
|
-
listener: (event?:
|
|
124
|
+
listener: (event?: Event) => void,
|
|
125
|
+
cancelSignal: CancellationSignal,
|
|
126
|
+
) => void;
|
|
127
|
+
|
|
128
|
+
function createCompatibleEventListener(
|
|
129
|
+
eventNames: string[] | Array<"needkey" | "encrypted">,
|
|
130
|
+
prefixes?: string[],
|
|
131
|
+
): (
|
|
132
|
+
element: IEventTargetLike,
|
|
133
|
+
listener: (event?: Event | MediaEncryptedEvent) => void,
|
|
108
134
|
cancelSignal: CancellationSignal,
|
|
109
135
|
) => void {
|
|
110
136
|
let mem: string | undefined;
|
|
@@ -112,13 +138,12 @@ function createCompatibleEventListener(
|
|
|
112
138
|
|
|
113
139
|
return (
|
|
114
140
|
element: IEventTargetLike,
|
|
115
|
-
listener: (event?:
|
|
141
|
+
listener: (event?: Event) => void,
|
|
116
142
|
cancelSignal: CancellationSignal,
|
|
117
143
|
) => {
|
|
118
144
|
if (cancelSignal.isCancelled()) {
|
|
119
145
|
return;
|
|
120
146
|
}
|
|
121
|
-
|
|
122
147
|
// if the element is a HTMLElement we can detect
|
|
123
148
|
// the supported event, and memoize it in `mem`
|
|
124
149
|
if (typeof HTMLElement !== "undefined" && element instanceof HTMLElement) {
|
|
@@ -1349,11 +1349,14 @@ function prettyPrintInventory(inventory: IBufferedChunk[]): string {
|
|
|
1349
1349
|
if (encounteredPeriod === undefined) {
|
|
1350
1350
|
currentLetter = generateNewLetter(chunk.infos);
|
|
1351
1351
|
encounteredReps[periodId] = { [representationId]: currentLetter };
|
|
1352
|
-
} else if (encounteredPeriod[representationId] === undefined) {
|
|
1353
|
-
currentLetter = generateNewLetter(chunk.infos);
|
|
1354
|
-
encounteredPeriod[representationId] = currentLetter;
|
|
1355
1352
|
} else {
|
|
1356
|
-
|
|
1353
|
+
const previousLetter = encounteredPeriod[representationId];
|
|
1354
|
+
if (previousLetter === undefined) {
|
|
1355
|
+
currentLetter = generateNewLetter(chunk.infos);
|
|
1356
|
+
encounteredPeriod[representationId] = currentLetter;
|
|
1357
|
+
} else {
|
|
1358
|
+
currentLetter = previousLetter;
|
|
1359
|
+
}
|
|
1357
1360
|
}
|
|
1358
1361
|
|
|
1359
1362
|
if (lastChunk === null) {
|
|
@@ -18,6 +18,7 @@ import { MediaError } from "../../errors";
|
|
|
18
18
|
import log from "../../log";
|
|
19
19
|
import type { IMediaSourceInterface } from "../../mse";
|
|
20
20
|
import { SourceBufferType } from "../../mse";
|
|
21
|
+
import assert from "../../utils/assert";
|
|
21
22
|
import createCancellablePromise from "../../utils/create_cancellable_promise";
|
|
22
23
|
import isNullOrUndefined from "../../utils/is_null_or_undefined";
|
|
23
24
|
import type { CancellationSignal } from "../../utils/task_canceller";
|
|
@@ -251,7 +252,8 @@ export default class SegmentSinksStore {
|
|
|
251
252
|
}
|
|
252
253
|
this._initializedSegmentSinks[bufferType] = null;
|
|
253
254
|
if (SegmentSinksStore.isNative(bufferType)) {
|
|
254
|
-
this._onNativeBufferAddedOrDisabled.forEach((cb) => cb());
|
|
255
|
+
this._onNativeBufferAddedOrDisabled.slice().forEach((cb) => cb());
|
|
256
|
+
assert(this._onNativeBufferAddedOrDisabled.length === 0);
|
|
255
257
|
}
|
|
256
258
|
}
|
|
257
259
|
|
|
@@ -295,7 +297,8 @@ export default class SegmentSinksStore {
|
|
|
295
297
|
this._mediaSource,
|
|
296
298
|
);
|
|
297
299
|
this._initializedSegmentSinks[bufferType] = nativeSegmentSink;
|
|
298
|
-
this._onNativeBufferAddedOrDisabled.forEach((cb) => cb());
|
|
300
|
+
this._onNativeBufferAddedOrDisabled.slice().forEach((cb) => cb());
|
|
301
|
+
assert(this._onNativeBufferAddedOrDisabled.length === 0);
|
|
299
302
|
return nativeSegmentSink;
|
|
300
303
|
}
|
|
301
304
|
|
|
@@ -409,7 +409,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
409
409
|
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
|
|
410
410
|
videoElement.preload = "auto";
|
|
411
411
|
|
|
412
|
-
this.version = /* PLAYER_VERSION */ "4.2.0-dev.
|
|
412
|
+
this.version = /* PLAYER_VERSION */ "4.2.0-dev.2024082600";
|
|
413
413
|
this.log = log;
|
|
414
414
|
this.state = "STOPPED";
|
|
415
415
|
this.videoElement = videoElement;
|
|
@@ -1889,10 +1889,18 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
1889
1889
|
/**
|
|
1890
1890
|
* Returns every available audio tracks for a given Period - or the current
|
|
1891
1891
|
* one if no `periodId` is given.
|
|
1892
|
-
* @param {string|undefined} [
|
|
1892
|
+
* @param {string|Object|undefined} [arg]
|
|
1893
1893
|
* @returns {Array.<Object>}
|
|
1894
1894
|
*/
|
|
1895
|
-
getAvailableAudioTracks(
|
|
1895
|
+
getAvailableAudioTracks(
|
|
1896
|
+
arg?:
|
|
1897
|
+
| string
|
|
1898
|
+
| undefined
|
|
1899
|
+
| {
|
|
1900
|
+
periodId: string;
|
|
1901
|
+
filterPlayableRepresentations: boolean;
|
|
1902
|
+
},
|
|
1903
|
+
): IAvailableAudioTrack[] {
|
|
1896
1904
|
if (this._priv_contentInfos === null) {
|
|
1897
1905
|
return [];
|
|
1898
1906
|
}
|
|
@@ -1900,10 +1908,20 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
1900
1908
|
if (isDirectFile) {
|
|
1901
1909
|
return mediaElementTracksStore?.getAvailableAudioTracks() ?? [];
|
|
1902
1910
|
}
|
|
1911
|
+
|
|
1912
|
+
let periodId: string | undefined;
|
|
1913
|
+
let filterPlayableRepresentations: boolean;
|
|
1914
|
+
if (typeof arg === "string") {
|
|
1915
|
+
periodId = arg;
|
|
1916
|
+
} else {
|
|
1917
|
+
periodId = arg?.periodId;
|
|
1918
|
+
filterPlayableRepresentations = arg?.filterPlayableRepresentations ?? true;
|
|
1919
|
+
}
|
|
1903
1920
|
return this._priv_callTracksStoreGetterSetter(
|
|
1904
1921
|
periodId,
|
|
1905
1922
|
[],
|
|
1906
|
-
(tcm, periodRef) =>
|
|
1923
|
+
(tcm, periodRef) =>
|
|
1924
|
+
tcm.getAvailableAudioTracks(periodRef, filterPlayableRepresentations) ?? [],
|
|
1907
1925
|
);
|
|
1908
1926
|
}
|
|
1909
1927
|
|
|
@@ -1930,10 +1948,18 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
1930
1948
|
|
|
1931
1949
|
/**
|
|
1932
1950
|
* Returns every available video tracks for the current Period.
|
|
1933
|
-
* @param {string|undefined} [
|
|
1951
|
+
* @param {string|Object|undefined} [arg]
|
|
1934
1952
|
* @returns {Array.<Object>}
|
|
1935
1953
|
*/
|
|
1936
|
-
getAvailableVideoTracks(
|
|
1954
|
+
getAvailableVideoTracks(
|
|
1955
|
+
arg?:
|
|
1956
|
+
| string
|
|
1957
|
+
| undefined
|
|
1958
|
+
| {
|
|
1959
|
+
periodId: string;
|
|
1960
|
+
filterPlayableRepresentations: boolean;
|
|
1961
|
+
},
|
|
1962
|
+
): IAvailableVideoTrack[] {
|
|
1937
1963
|
if (this._priv_contentInfos === null) {
|
|
1938
1964
|
return [];
|
|
1939
1965
|
}
|
|
@@ -1941,19 +1967,37 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
1941
1967
|
if (isDirectFile) {
|
|
1942
1968
|
return mediaElementTracksStore?.getAvailableVideoTracks() ?? [];
|
|
1943
1969
|
}
|
|
1970
|
+
|
|
1971
|
+
let periodId: string | undefined;
|
|
1972
|
+
let filterPlayableRepresentations: boolean;
|
|
1973
|
+
if (typeof arg === "string") {
|
|
1974
|
+
periodId = arg;
|
|
1975
|
+
} else {
|
|
1976
|
+
periodId = arg?.periodId;
|
|
1977
|
+
filterPlayableRepresentations = arg?.filterPlayableRepresentations ?? true;
|
|
1978
|
+
}
|
|
1944
1979
|
return this._priv_callTracksStoreGetterSetter(
|
|
1945
1980
|
periodId,
|
|
1946
1981
|
[],
|
|
1947
|
-
(tcm, periodRef) =>
|
|
1982
|
+
(tcm, periodRef) =>
|
|
1983
|
+
tcm.getAvailableVideoTracks(periodRef, filterPlayableRepresentations) ?? [],
|
|
1948
1984
|
);
|
|
1949
1985
|
}
|
|
1950
1986
|
|
|
1951
1987
|
/**
|
|
1952
1988
|
* Returns currently chosen audio language for the current Period.
|
|
1953
|
-
* @param {string|undefined} [
|
|
1989
|
+
* @param {string|Object|undefined} [arg]
|
|
1954
1990
|
* @returns {Object|null|undefined}
|
|
1955
1991
|
*/
|
|
1956
|
-
getAudioTrack(
|
|
1992
|
+
getAudioTrack(
|
|
1993
|
+
arg?:
|
|
1994
|
+
| string
|
|
1995
|
+
| undefined
|
|
1996
|
+
| {
|
|
1997
|
+
periodId: string;
|
|
1998
|
+
filterPlayableRepresentations: boolean;
|
|
1999
|
+
},
|
|
2000
|
+
): IAudioTrack | null | undefined {
|
|
1957
2001
|
if (this._priv_contentInfos === null) {
|
|
1958
2002
|
return undefined;
|
|
1959
2003
|
}
|
|
@@ -1964,8 +2008,17 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
1964
2008
|
}
|
|
1965
2009
|
return mediaElementTracksStore.getChosenAudioTrack();
|
|
1966
2010
|
}
|
|
2011
|
+
|
|
2012
|
+
let periodId: string | undefined;
|
|
2013
|
+
let filterPlayableRepresentations: boolean;
|
|
2014
|
+
if (typeof arg === "string") {
|
|
2015
|
+
periodId = arg;
|
|
2016
|
+
} else {
|
|
2017
|
+
periodId = arg?.periodId;
|
|
2018
|
+
filterPlayableRepresentations = arg?.filterPlayableRepresentations ?? true;
|
|
2019
|
+
}
|
|
1967
2020
|
return this._priv_callTracksStoreGetterSetter(periodId, undefined, (tcm, periodRef) =>
|
|
1968
|
-
tcm.getChosenAudioTrack(periodRef),
|
|
2021
|
+
tcm.getChosenAudioTrack(periodRef, filterPlayableRepresentations),
|
|
1969
2022
|
);
|
|
1970
2023
|
}
|
|
1971
2024
|
|
|
@@ -1992,10 +2045,18 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
1992
2045
|
|
|
1993
2046
|
/**
|
|
1994
2047
|
* Returns currently chosen video track for the current Period.
|
|
1995
|
-
* @param {string|undefined} [
|
|
2048
|
+
* @param {string|Object|undefined} [arg]
|
|
1996
2049
|
* @returns {Object|null|undefined}
|
|
1997
2050
|
*/
|
|
1998
|
-
getVideoTrack(
|
|
2051
|
+
getVideoTrack(
|
|
2052
|
+
arg?:
|
|
2053
|
+
| string
|
|
2054
|
+
| undefined
|
|
2055
|
+
| {
|
|
2056
|
+
periodId: string;
|
|
2057
|
+
filterPlayableRepresentations: boolean;
|
|
2058
|
+
},
|
|
2059
|
+
): IVideoTrack | null | undefined {
|
|
1999
2060
|
if (this._priv_contentInfos === null) {
|
|
2000
2061
|
return undefined;
|
|
2001
2062
|
}
|
|
@@ -2006,8 +2067,17 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
2006
2067
|
}
|
|
2007
2068
|
return mediaElementTracksStore.getChosenVideoTrack();
|
|
2008
2069
|
}
|
|
2070
|
+
|
|
2071
|
+
let periodId: string | undefined;
|
|
2072
|
+
let filterPlayableRepresentations: boolean;
|
|
2073
|
+
if (typeof arg === "string") {
|
|
2074
|
+
periodId = arg;
|
|
2075
|
+
} else {
|
|
2076
|
+
periodId = arg?.periodId;
|
|
2077
|
+
filterPlayableRepresentations = arg?.filterPlayableRepresentations ?? true;
|
|
2078
|
+
}
|
|
2009
2079
|
return this._priv_callTracksStoreGetterSetter(periodId, undefined, (tcm, periodRef) =>
|
|
2010
|
-
tcm.getChosenVideoTrack(periodRef),
|
|
2080
|
+
tcm.getChosenVideoTrack(periodRef, filterPlayableRepresentations),
|
|
2011
2081
|
);
|
|
2012
2082
|
}
|
|
2013
2083
|
|
|
@@ -2612,10 +2682,12 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
2612
2682
|
}
|
|
2613
2683
|
switch (elt.adaptation.type) {
|
|
2614
2684
|
case "audio":
|
|
2615
|
-
isCurrent =
|
|
2685
|
+
isCurrent =
|
|
2686
|
+
tStore.getChosenAudioTrack(periodRef, false)?.id === elt.adaptation.id;
|
|
2616
2687
|
break;
|
|
2617
2688
|
case "video":
|
|
2618
|
-
isCurrent =
|
|
2689
|
+
isCurrent =
|
|
2690
|
+
tStore.getChosenVideoTrack(periodRef, false)?.id === elt.adaptation.id;
|
|
2619
2691
|
break;
|
|
2620
2692
|
case "text":
|
|
2621
2693
|
isCurrent = tStore.getChosenTextTrack(periodRef)?.id === elt.adaptation.id;
|
|
@@ -2690,11 +2762,11 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
2690
2762
|
if (!isNullOrUndefined(tracksStore)) {
|
|
2691
2763
|
const periodRef = tracksStore.getPeriodObjectFromPeriod(period);
|
|
2692
2764
|
if (periodRef) {
|
|
2693
|
-
const audioTrack = tracksStore.getChosenAudioTrack(periodRef);
|
|
2765
|
+
const audioTrack = tracksStore.getChosenAudioTrack(periodRef, true);
|
|
2694
2766
|
this._priv_triggerEventIfNotStopped("audioTrackChange", audioTrack, cancelSignal);
|
|
2695
2767
|
const textTrack = tracksStore.getChosenTextTrack(periodRef);
|
|
2696
2768
|
this._priv_triggerEventIfNotStopped("textTrackChange", textTrack, cancelSignal);
|
|
2697
|
-
const videoTrack = tracksStore.getChosenVideoTrack(periodRef);
|
|
2769
|
+
const videoTrack = tracksStore.getChosenVideoTrack(periodRef, true);
|
|
2698
2770
|
this._priv_triggerEventIfNotStopped("videoTrackChange", videoTrack, cancelSignal);
|
|
2699
2771
|
}
|
|
2700
2772
|
} else {
|
|
@@ -2854,7 +2926,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
2854
2926
|
}
|
|
2855
2927
|
switch (type) {
|
|
2856
2928
|
case "audio":
|
|
2857
|
-
const audioTrack = tracksStore.getChosenAudioTrack(periodRef);
|
|
2929
|
+
const audioTrack = tracksStore.getChosenAudioTrack(periodRef, true);
|
|
2858
2930
|
this._priv_triggerEventIfNotStopped(
|
|
2859
2931
|
"audioTrackChange",
|
|
2860
2932
|
audioTrack,
|
|
@@ -2866,7 +2938,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
2866
2938
|
this._priv_triggerEventIfNotStopped("textTrackChange", textTrack, cancelSignal);
|
|
2867
2939
|
break;
|
|
2868
2940
|
case "video":
|
|
2869
|
-
const videoTrack = tracksStore.getChosenVideoTrack(periodRef);
|
|
2941
|
+
const videoTrack = tracksStore.getChosenVideoTrack(periodRef, true);
|
|
2870
2942
|
this._priv_triggerEventIfNotStopped(
|
|
2871
2943
|
"videoTrackChange",
|
|
2872
2944
|
videoTrack,
|
|
@@ -3178,7 +3250,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
3178
3250
|
}
|
|
3179
3251
|
switch (trackType) {
|
|
3180
3252
|
case "video":
|
|
3181
|
-
const videoTracks = tracksStore.getAvailableVideoTracks(periodRef);
|
|
3253
|
+
const videoTracks = tracksStore.getAvailableVideoTracks(periodRef, true);
|
|
3182
3254
|
this._priv_triggerEventIfNotStopped(
|
|
3183
3255
|
"availableVideoTracksChange",
|
|
3184
3256
|
videoTracks ?? [],
|
|
@@ -3186,7 +3258,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
3186
3258
|
);
|
|
3187
3259
|
break;
|
|
3188
3260
|
case "audio":
|
|
3189
|
-
const audioTracks = tracksStore.getAvailableAudioTracks(periodRef);
|
|
3261
|
+
const audioTracks = tracksStore.getAvailableAudioTracks(periodRef, true);
|
|
3190
3262
|
this._priv_triggerEventIfNotStopped(
|
|
3191
3263
|
"availableAudioTracksChange",
|
|
3192
3264
|
audioTracks ?? [],
|
|
@@ -3235,7 +3307,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
3235
3307
|
}
|
|
3236
3308
|
}
|
|
3237
3309
|
}
|
|
3238
|
-
Player.version = /* PLAYER_VERSION */ "4.2.0-dev.
|
|
3310
|
+
Player.version = /* PLAYER_VERSION */ "4.2.0-dev.2024082600";
|
|
3239
3311
|
|
|
3240
3312
|
/** Every events sent by the RxPlayer's public API. */
|
|
3241
3313
|
interface IPublicAPIEvent {
|
|
@@ -3244,8 +3316,8 @@ interface IPublicAPIEvent {
|
|
|
3244
3316
|
audioTrackChange: IAudioTrack | null;
|
|
3245
3317
|
textTrackChange: ITextTrack | null;
|
|
3246
3318
|
videoTrackChange: IVideoTrack | null;
|
|
3247
|
-
audioRepresentationChange:
|
|
3248
|
-
videoRepresentationChange:
|
|
3319
|
+
audioRepresentationChange: IAudioRepresentation | null;
|
|
3320
|
+
videoRepresentationChange: IVideoRepresentation | null;
|
|
3249
3321
|
volumeChange: {
|
|
3250
3322
|
volume: number;
|
|
3251
3323
|
muted: boolean;
|
|
@@ -177,7 +177,7 @@ export default class ContentDecryptor extends EventEmitter<IContentDecryptorEven
|
|
|
177
177
|
mediaElement,
|
|
178
178
|
(evt) => {
|
|
179
179
|
log.debug("DRM: Encrypted event received from media element.");
|
|
180
|
-
const initData = getInitData(evt
|
|
180
|
+
const initData = getInitData(evt);
|
|
181
181
|
if (initData !== null) {
|
|
182
182
|
this.onInitializationData(initData);
|
|
183
183
|
}
|
|
@@ -730,6 +730,21 @@ export default class ContentDecryptor extends EventEmitter<IContentDecryptorEven
|
|
|
730
730
|
return false;
|
|
731
731
|
}
|
|
732
732
|
|
|
733
|
+
/**
|
|
734
|
+
* On Safari using Directfile, the old EME implementation triggers
|
|
735
|
+
* the "webkitneedkey" event instead of "encrypted". There's an issue in Safari
|
|
736
|
+
* where "webkitneedkey" fires too early before all tracks are added from an HLS playlist.
|
|
737
|
+
* Safari incorrectly assumes some keys are missing for these tracks,
|
|
738
|
+
* leading to repeated "webkitneedkey" events. Because RxPlayer recognizes
|
|
739
|
+
* it already has a session for these keys and ignores the events,
|
|
740
|
+
* the content remains frozen. To resolve this, the session is re-created.
|
|
741
|
+
*/
|
|
742
|
+
const forceSessionRecreation = initializationData.forceSessionRecreation;
|
|
743
|
+
if (forceSessionRecreation === true) {
|
|
744
|
+
this.removeSessionForInitData(initializationData, mediaKeysData);
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
|
|
733
748
|
// Check if the compatible session is blacklisted
|
|
734
749
|
const blacklistedSessionError = compatibleSessionInfo.blacklistedSessionError;
|
|
735
750
|
if (!isNullOrUndefined(blacklistedSessionError)) {
|
|
@@ -834,6 +849,48 @@ export default class ContentDecryptor extends EventEmitter<IContentDecryptorEven
|
|
|
834
849
|
return false;
|
|
835
850
|
}
|
|
836
851
|
|
|
852
|
+
/**
|
|
853
|
+
* Remove the session corresponding to the initData provided, and close it.
|
|
854
|
+
* It does nothing if no session was found for this initData.
|
|
855
|
+
* @param {Object} initData : The initialization data corresponding to the session
|
|
856
|
+
* that need to be removed
|
|
857
|
+
* @param {Object} mediaKeysData : The media keys data
|
|
858
|
+
*/
|
|
859
|
+
private removeSessionForInitData(
|
|
860
|
+
initData: IProcessedProtectionData,
|
|
861
|
+
mediaKeysData: IAttachedMediaKeysData,
|
|
862
|
+
) {
|
|
863
|
+
const { stores } = mediaKeysData;
|
|
864
|
+
/** Remove the session and close it from the loadedSessionStore */
|
|
865
|
+
const entry = stores.loadedSessionsStore.reuse(initData);
|
|
866
|
+
if (entry !== null) {
|
|
867
|
+
stores.loadedSessionsStore
|
|
868
|
+
.closeSession(entry.mediaKeySession)
|
|
869
|
+
.catch(() =>
|
|
870
|
+
log.error("DRM: Cannot close the session from the loaded session store"),
|
|
871
|
+
);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* If set, a currently-used key session is already compatible to this
|
|
876
|
+
* initialization data.
|
|
877
|
+
*/
|
|
878
|
+
const compatibleSessionInfo = arrayFind(this._currentSessions, (x) =>
|
|
879
|
+
x.record.isCompatibleWith(initData),
|
|
880
|
+
);
|
|
881
|
+
if (compatibleSessionInfo === undefined) {
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
/** Remove the session from the currentSessions */
|
|
885
|
+
const indexOf = this._currentSessions.indexOf(compatibleSessionInfo);
|
|
886
|
+
if (indexOf !== -1) {
|
|
887
|
+
log.debug(
|
|
888
|
+
"DRM: A session from a processed init is removed due to forceSessionRecreation policy.",
|
|
889
|
+
);
|
|
890
|
+
this._currentSessions.splice(indexOf, 1);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
837
894
|
/**
|
|
838
895
|
* Callback that should be called if an error that made the current
|
|
839
896
|
* `ContentDecryptor` instance unusable arised.
|
|
@@ -1147,8 +1204,8 @@ function addKeyIdsFromPeriod(set: Set<Uint8Array>, period: IPeriodMetadata) {
|
|
|
1147
1204
|
representation.contentProtections !== undefined &&
|
|
1148
1205
|
representation.contentProtections.keyIds !== undefined
|
|
1149
1206
|
) {
|
|
1150
|
-
for (const
|
|
1151
|
-
set.add(
|
|
1207
|
+
for (const kid of representation.contentProtections.keyIds) {
|
|
1208
|
+
set.add(kid);
|
|
1152
1209
|
}
|
|
1153
1210
|
}
|
|
1154
1211
|
}
|
|
@@ -127,6 +127,11 @@ export interface IProtectionData {
|
|
|
127
127
|
/** Protection initialization data actually processed by the `ContentDecryptor`. */
|
|
128
128
|
export interface IProcessedProtectionData extends Omit<IProtectionData, "values"> {
|
|
129
129
|
values: InitDataValuesContainer;
|
|
130
|
+
/**
|
|
131
|
+
* Enforce to recreate the media key session if there is already a session created
|
|
132
|
+
* with this init data
|
|
133
|
+
*/
|
|
134
|
+
forceSessionRecreation?: boolean | undefined;
|
|
130
135
|
}
|
|
131
136
|
|
|
132
137
|
/**
|
|
@@ -1267,17 +1267,17 @@ function updateKeyIdsDecipherabilityOnManifest(
|
|
|
1267
1267
|
if (contentKIDs !== undefined) {
|
|
1268
1268
|
for (const elt of contentKIDs) {
|
|
1269
1269
|
for (const blacklistedKeyId of blacklistedKeyIds) {
|
|
1270
|
-
if (areArraysOfNumbersEqual(blacklistedKeyId, elt
|
|
1270
|
+
if (areArraysOfNumbersEqual(blacklistedKeyId, elt)) {
|
|
1271
1271
|
return false;
|
|
1272
1272
|
}
|
|
1273
1273
|
}
|
|
1274
1274
|
for (const whitelistedKeyId of whitelistedKeyIds) {
|
|
1275
|
-
if (areArraysOfNumbersEqual(whitelistedKeyId, elt
|
|
1275
|
+
if (areArraysOfNumbersEqual(whitelistedKeyId, elt)) {
|
|
1276
1276
|
return true;
|
|
1277
1277
|
}
|
|
1278
1278
|
}
|
|
1279
1279
|
for (const delistedKeyId of delistedKeyIds) {
|
|
1280
|
-
if (areArraysOfNumbersEqual(delistedKeyId, elt
|
|
1280
|
+
if (areArraysOfNumbersEqual(delistedKeyId, elt)) {
|
|
1281
1281
|
return undefined;
|
|
1282
1282
|
}
|
|
1283
1283
|
}
|