rx-player 4.2.0-dev.2024081400 → 4.2.0-dev.2024090300

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.
Files changed (137) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/VERSION +1 -1
  3. package/dist/commonjs/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
  4. package/dist/commonjs/__GENERATED_CODE/embedded_worker.js +1 -1
  5. package/dist/commonjs/compat/browser_detection.d.ts +3 -1
  6. package/dist/commonjs/compat/browser_detection.d.ts.map +1 -1
  7. package/dist/commonjs/compat/browser_detection.js +8 -1
  8. package/dist/commonjs/compat/can_reuse_media_keys.d.ts +2 -0
  9. package/dist/commonjs/compat/can_reuse_media_keys.d.ts.map +1 -1
  10. package/dist/commonjs/compat/can_reuse_media_keys.js +3 -1
  11. package/dist/commonjs/compat/eme/custom_media_keys/types.d.ts +3 -0
  12. package/dist/commonjs/compat/eme/custom_media_keys/types.d.ts.map +1 -1
  13. package/dist/commonjs/compat/eme/custom_media_keys/webkit_media_keys.d.ts +1 -1
  14. package/dist/commonjs/compat/eme/custom_media_keys/webkit_media_keys.d.ts.map +1 -1
  15. package/dist/commonjs/compat/eme/eme-api-implementation.d.ts +2 -2
  16. package/dist/commonjs/compat/eme/eme-api-implementation.d.ts.map +1 -1
  17. package/dist/commonjs/compat/eme/eme-api-implementation.js +19 -2
  18. package/dist/commonjs/compat/eme/get_init_data.d.ts +3 -1
  19. package/dist/commonjs/compat/eme/get_init_data.d.ts.map +1 -1
  20. package/dist/commonjs/compat/eme/get_init_data.js +2 -2
  21. package/dist/commonjs/compat/event_listeners.d.ts +21 -19
  22. package/dist/commonjs/compat/event_listeners.d.ts.map +1 -1
  23. package/dist/commonjs/compat/event_listeners.js +0 -11
  24. package/dist/commonjs/core/cmcd/cmcd_data_builder.js +1 -1
  25. package/dist/commonjs/core/main/worker/worker_main.js +1 -0
  26. package/dist/commonjs/core/segment_sinks/inventory/segment_inventory.js +8 -5
  27. package/dist/commonjs/main_thread/api/public_api.d.ts +22 -10
  28. package/dist/commonjs/main_thread/api/public_api.d.ts.map +1 -1
  29. package/dist/commonjs/main_thread/api/public_api.js +68 -28
  30. package/dist/commonjs/main_thread/decrypt/content_decryptor.d.ts +8 -0
  31. package/dist/commonjs/main_thread/decrypt/content_decryptor.d.ts.map +1 -1
  32. package/dist/commonjs/main_thread/decrypt/content_decryptor.js +51 -2
  33. package/dist/commonjs/main_thread/decrypt/types.d.ts +5 -0
  34. package/dist/commonjs/main_thread/decrypt/types.d.ts.map +1 -1
  35. package/dist/commonjs/main_thread/init/media_source_content_initializer.js +3 -3
  36. package/dist/commonjs/main_thread/tracks_store/tracks_store.d.ts +12 -4
  37. package/dist/commonjs/main_thread/tracks_store/tracks_store.d.ts.map +1 -1
  38. package/dist/commonjs/main_thread/tracks_store/tracks_store.js +18 -8
  39. package/dist/commonjs/manifest/classes/adaptation.d.ts +13 -13
  40. package/dist/commonjs/manifest/classes/adaptation.d.ts.map +1 -1
  41. package/dist/commonjs/manifest/classes/adaptation.js +1 -4
  42. package/dist/commonjs/manifest/classes/representation.d.ts +20 -12
  43. package/dist/commonjs/manifest/classes/representation.d.ts.map +1 -1
  44. package/dist/commonjs/manifest/classes/representation.js +8 -8
  45. package/dist/commonjs/manifest/utils.d.ts +4 -3
  46. package/dist/commonjs/manifest/utils.d.ts.map +1 -1
  47. package/dist/commonjs/manifest/utils.js +13 -7
  48. package/dist/commonjs/parsers/manifest/dash/common/content_protection_parser.js +4 -4
  49. package/dist/commonjs/parsers/manifest/local/parse_local_manifest.js +1 -1
  50. package/dist/commonjs/parsers/manifest/smooth/create_parser.d.ts.map +1 -1
  51. package/dist/commonjs/parsers/manifest/smooth/create_parser.js +1 -4
  52. package/dist/commonjs/parsers/manifest/types.d.ts +1 -6
  53. package/dist/commonjs/parsers/manifest/types.d.ts.map +1 -1
  54. package/dist/commonjs/public_types.d.ts +69 -0
  55. package/dist/commonjs/public_types.d.ts.map +1 -1
  56. package/dist/es2017/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
  57. package/dist/es2017/__GENERATED_CODE/embedded_worker.js +1 -1
  58. package/dist/es2017/compat/browser_detection.d.ts +3 -1
  59. package/dist/es2017/compat/browser_detection.d.ts.map +1 -1
  60. package/dist/es2017/compat/browser_detection.js +7 -1
  61. package/dist/es2017/compat/can_reuse_media_keys.d.ts +2 -0
  62. package/dist/es2017/compat/can_reuse_media_keys.d.ts.map +1 -1
  63. package/dist/es2017/compat/can_reuse_media_keys.js +4 -2
  64. package/dist/es2017/compat/eme/custom_media_keys/types.d.ts +3 -0
  65. package/dist/es2017/compat/eme/custom_media_keys/types.d.ts.map +1 -1
  66. package/dist/es2017/compat/eme/custom_media_keys/webkit_media_keys.d.ts +1 -1
  67. package/dist/es2017/compat/eme/custom_media_keys/webkit_media_keys.d.ts.map +1 -1
  68. package/dist/es2017/compat/eme/eme-api-implementation.d.ts +2 -2
  69. package/dist/es2017/compat/eme/eme-api-implementation.d.ts.map +1 -1
  70. package/dist/es2017/compat/eme/eme-api-implementation.js +19 -2
  71. package/dist/es2017/compat/eme/get_init_data.d.ts +3 -1
  72. package/dist/es2017/compat/eme/get_init_data.d.ts.map +1 -1
  73. package/dist/es2017/compat/eme/get_init_data.js +2 -2
  74. package/dist/es2017/compat/event_listeners.d.ts +21 -19
  75. package/dist/es2017/compat/event_listeners.d.ts.map +1 -1
  76. package/dist/es2017/compat/event_listeners.js +0 -11
  77. package/dist/es2017/core/cmcd/cmcd_data_builder.js +1 -1
  78. package/dist/es2017/core/main/worker/worker_main.js +1 -0
  79. package/dist/es2017/core/segment_sinks/inventory/segment_inventory.js +8 -5
  80. package/dist/es2017/main_thread/api/public_api.d.ts +22 -10
  81. package/dist/es2017/main_thread/api/public_api.d.ts.map +1 -1
  82. package/dist/es2017/main_thread/api/public_api.js +64 -24
  83. package/dist/es2017/main_thread/decrypt/content_decryptor.d.ts +8 -0
  84. package/dist/es2017/main_thread/decrypt/content_decryptor.d.ts.map +1 -1
  85. package/dist/es2017/main_thread/decrypt/content_decryptor.js +47 -2
  86. package/dist/es2017/main_thread/decrypt/types.d.ts +5 -0
  87. package/dist/es2017/main_thread/decrypt/types.d.ts.map +1 -1
  88. package/dist/es2017/main_thread/init/media_source_content_initializer.js +3 -3
  89. package/dist/es2017/main_thread/tracks_store/tracks_store.d.ts +12 -4
  90. package/dist/es2017/main_thread/tracks_store/tracks_store.d.ts.map +1 -1
  91. package/dist/es2017/main_thread/tracks_store/tracks_store.js +18 -8
  92. package/dist/es2017/manifest/classes/adaptation.d.ts +13 -13
  93. package/dist/es2017/manifest/classes/adaptation.d.ts.map +1 -1
  94. package/dist/es2017/manifest/classes/adaptation.js +1 -1
  95. package/dist/es2017/manifest/classes/representation.d.ts +20 -12
  96. package/dist/es2017/manifest/classes/representation.d.ts.map +1 -1
  97. package/dist/es2017/manifest/classes/representation.js +8 -8
  98. package/dist/es2017/manifest/utils.d.ts +4 -3
  99. package/dist/es2017/manifest/utils.d.ts.map +1 -1
  100. package/dist/es2017/manifest/utils.js +13 -7
  101. package/dist/es2017/parsers/manifest/dash/common/content_protection_parser.js +4 -4
  102. package/dist/es2017/parsers/manifest/local/parse_local_manifest.js +1 -1
  103. package/dist/es2017/parsers/manifest/smooth/create_parser.d.ts.map +1 -1
  104. package/dist/es2017/parsers/manifest/smooth/create_parser.js +1 -4
  105. package/dist/es2017/parsers/manifest/types.d.ts +1 -6
  106. package/dist/es2017/parsers/manifest/types.d.ts.map +1 -1
  107. package/dist/es2017/public_types.d.ts +69 -0
  108. package/dist/es2017/public_types.d.ts.map +1 -1
  109. package/dist/rx-player.js +18 -18
  110. package/dist/worker.js +5 -5
  111. package/package.json +2 -2
  112. package/src/__GENERATED_CODE/embedded_worker.ts +1 -1
  113. package/src/compat/__tests__/can_reuse_media_keys.test.ts +33 -2
  114. package/src/compat/browser_detection.ts +9 -0
  115. package/src/compat/can_reuse_media_keys.ts +4 -2
  116. package/src/compat/eme/custom_media_keys/types.ts +4 -0
  117. package/src/compat/eme/custom_media_keys/webkit_media_keys.ts +1 -1
  118. package/src/compat/eme/eme-api-implementation.ts +35 -4
  119. package/src/compat/eme/get_init_data.ts +5 -3
  120. package/src/compat/event_listeners.ts +30 -5
  121. package/src/core/cmcd/cmcd_data_builder.ts +1 -1
  122. package/src/core/main/worker/worker_main.ts +1 -0
  123. package/src/core/segment_sinks/inventory/segment_inventory.ts +7 -4
  124. package/src/main_thread/api/public_api.ts +96 -24
  125. package/src/main_thread/decrypt/content_decryptor.ts +60 -3
  126. package/src/main_thread/decrypt/types.ts +5 -0
  127. package/src/main_thread/init/media_source_content_initializer.ts +3 -3
  128. package/src/main_thread/tracks_store/tracks_store.ts +30 -6
  129. package/src/manifest/classes/adaptation.ts +14 -16
  130. package/src/manifest/classes/representation.ts +26 -18
  131. package/src/manifest/utils.ts +14 -6
  132. package/src/parsers/manifest/dash/common/content_protection_parser.ts +4 -4
  133. package/src/parsers/manifest/local/parse_local_manifest.ts +1 -1
  134. package/src/parsers/manifest/smooth/create_parser.ts +2 -6
  135. package/src/parsers/manifest/types.ts +1 -7
  136. package/src/public_types.ts +73 -0
  137. package/vitest.config.mjs +1 -0
@@ -10,9 +10,9 @@ describe("Compat - canReuseMediaKeys", () => {
10
10
  vi.resetModules();
11
11
  });
12
12
 
13
- it("should return true on any browser but WebOS", async () => {
13
+ it("should return true on most browsers", async () => {
14
14
  vi.doMock("../browser_detection", () => {
15
- return { isWebOs: false, isPanasonic: false };
15
+ return { isWebOs: false, isPhilipsNetTv: false, isPanasonic: false };
16
16
  });
17
17
  const canReuseMediaKeys = (await vi.importActual(
18
18
  "../can_reuse_media_keys.ts",
@@ -26,6 +26,37 @@ describe("Compat - canReuseMediaKeys", () => {
26
26
  isWebOs: true,
27
27
  isWebOs2022: false,
28
28
  isPanasonic: false,
29
+ isPhilipsNetTv: false,
30
+ };
31
+ });
32
+ const canReuseMediaKeys = (await vi.importActual(
33
+ "../can_reuse_media_keys.ts",
34
+ )) as any;
35
+ expect(canReuseMediaKeys.default()).toBe(false);
36
+ });
37
+
38
+ it("should return false on Panasonic", async () => {
39
+ vi.doMock("../browser_detection", () => {
40
+ return {
41
+ isWebOs: false,
42
+ isWebOs2022: false,
43
+ isPanasonic: true,
44
+ isPhilipsNetTv: false,
45
+ };
46
+ });
47
+ const canReuseMediaKeys = (await vi.importActual(
48
+ "../can_reuse_media_keys.ts",
49
+ )) as any;
50
+ expect(canReuseMediaKeys.default()).toBe(false);
51
+ });
52
+
53
+ it("should return false on Philips' NETTV", async () => {
54
+ vi.doMock("../browser_detection", () => {
55
+ return {
56
+ isWebOs: false,
57
+ isWebOs2022: false,
58
+ isPanasonic: false,
59
+ isPhilipsNetTv: true,
29
60
  };
30
61
  });
31
62
  const canReuseMediaKeys = (await vi.importActual(
@@ -67,6 +67,9 @@ let isWebOs2022 = false;
67
67
  /** `true` for Panasonic devices. */
68
68
  let isPanasonic = false;
69
69
 
70
+ /** `true` we're relying on Philips's NetTv browser. */
71
+ let isPhilipsNetTv = false;
72
+
70
73
  /** `true` for the PlayStation 4 game console. */
71
74
  let isPlayStation4 = false;
72
75
 
@@ -155,6 +158,11 @@ let isXbox = false;
155
158
  ) {
156
159
  isWebOs2021 = true;
157
160
  }
161
+ } else if (
162
+ navigator.userAgent.indexOf("NETTV") !== -1 &&
163
+ navigator.userAgent.indexOf("Philips") !== -1
164
+ ) {
165
+ isPhilipsNetTv = true;
158
166
  } else if (/[Pp]anasonic/.test(navigator.userAgent)) {
159
167
  isPanasonic = true;
160
168
  } else if (navigator.userAgent.indexOf("Xbox") !== -1) {
@@ -168,6 +176,7 @@ export {
168
176
  isIEOrEdge,
169
177
  isFirefox,
170
178
  isPanasonic,
179
+ isPhilipsNetTv,
171
180
  isPlayStation4,
172
181
  isPlayStation5,
173
182
  isXbox,
@@ -1,4 +1,4 @@
1
- import { isPanasonic, isWebOs } from "./browser_detection";
1
+ import { isPanasonic, isPhilipsNetTv, isWebOs } from "./browser_detection";
2
2
 
3
3
  /**
4
4
  * Returns `true` if a `MediaKeys` instance (the `Encrypted Media Extension`
@@ -9,9 +9,11 @@ import { isPanasonic, isWebOs } from "./browser_detection";
9
9
  * - (2022-11-21): WebOS (LG TVs), for some encrypted contents, just
10
10
  * rebuffered indefinitely when loading a content already-loaded on the
11
11
  * HTMLMediaElement.
12
+ * - (2024-08-23): Seen on Philips 2024 and 2023 in:
13
+ * https://github.com/canalplus/rx-player/issues/1464
12
14
  *
13
15
  * @returns {boolean}
14
16
  */
15
17
  export default function canReuseMediaKeys(): boolean {
16
- return !isWebOs && !isPanasonic;
18
+ return !isWebOs && !isPhilipsNetTv && !isPanasonic;
17
19
  }
@@ -60,3 +60,7 @@ export interface IMediaKeySessionEvents {
60
60
  // "keyerror"
61
61
  /* "error" */
62
62
  }
63
+
64
+ export interface ICustomMediaEncryptedEvent extends MediaEncryptedEvent {
65
+ forceSessionRecreation?: boolean | undefined;
66
+ }
@@ -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) => void;
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 { ICustomMediaKeys } from "./custom_media_keys/types";
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: unknown) => void,
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 = createCompatibleEventListener(["needkey"]);
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: MediaEncryptedEvent,
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: (eventName: string, handler: () => void) => void;
86
- removeEventListener: (eventName: string, handler: () => void) => void;
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?: unknown) => void,
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?: unknown) => void,
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) {
@@ -377,8 +377,8 @@ export default class CmcdDataBuilder {
377
377
  }
378
378
  };
379
379
 
380
- addNumberProperty("br", "object");
381
380
  addNumberProperty("bl", "request");
381
+ addNumberProperty("br", "object");
382
382
  addBooleanProperty("bs", "status");
383
383
  addStringProperty("cid", "session");
384
384
  addNumberProperty("d", "object");
@@ -744,6 +744,7 @@ function loadOrReloadPreparedContent(
744
744
  }
745
745
  }
746
746
 
747
+ contentTimeBoundariesObserver.onPeriodCleared(value.type, value.period);
747
748
  preparedContent.trackChoiceSetter.removeTrackSetter(value.period.id, value.type);
748
749
  sendMessage({
749
750
  type: WorkerMessageType.PeriodStreamCleared,
@@ -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
- currentLetter = encounteredPeriod[representationId];
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) {
@@ -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.2024081400";
412
+ this.version = /* PLAYER_VERSION */ "4.2.0-dev.2024090300";
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} [periodId]
1892
+ * @param {string|Object|undefined} [arg]
1893
1893
  * @returns {Array.<Object>}
1894
1894
  */
1895
- getAvailableAudioTracks(periodId?: string | undefined): IAvailableAudioTrack[] {
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) => tcm.getAvailableAudioTracks(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} [periodId]
1951
+ * @param {string|Object|undefined} [arg]
1934
1952
  * @returns {Array.<Object>}
1935
1953
  */
1936
- getAvailableVideoTracks(periodId?: string | undefined): IAvailableVideoTrack[] {
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) => tcm.getAvailableVideoTracks(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} [periodId]
1989
+ * @param {string|Object|undefined} [arg]
1954
1990
  * @returns {Object|null|undefined}
1955
1991
  */
1956
- getAudioTrack(periodId?: string | undefined): IAudioTrack | null | undefined {
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} [periodId]
2048
+ * @param {string|Object|undefined} [arg]
1996
2049
  * @returns {Object|null|undefined}
1997
2050
  */
1998
- getVideoTrack(periodId?: string | undefined): IVideoTrack | null | undefined {
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 = tStore.getChosenAudioTrack(periodRef)?.id === elt.adaptation.id;
2685
+ isCurrent =
2686
+ tStore.getChosenAudioTrack(periodRef, false)?.id === elt.adaptation.id;
2616
2687
  break;
2617
2688
  case "video":
2618
- isCurrent = tStore.getChosenVideoTrack(periodRef)?.id === elt.adaptation.id;
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.2024081400";
3310
+ Player.version = /* PLAYER_VERSION */ "4.2.0-dev.2024090300";
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: IVideoRepresentation | null;
3248
- videoRepresentationChange: IAudioRepresentation | null;
3319
+ audioRepresentationChange: IAudioRepresentation | null;
3320
+ videoRepresentationChange: IVideoRepresentation | null;
3249
3321
  volumeChange: {
3250
3322
  volume: number;
3251
3323
  muted: boolean;