rx-player 4.3.0-dev.2024112900 → 4.3.0-dev.2025012900

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 (174) hide show
  1. package/CHANGELOG.md +30 -8
  2. package/VERSION +1 -1
  3. package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.d.ts +1 -1
  4. package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
  5. package/dist/commonjs/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
  6. package/dist/commonjs/__GENERATED_CODE/embedded_worker.js +1 -1
  7. package/dist/commonjs/compat/browser_compatibility_types.d.ts +7 -2
  8. package/dist/commonjs/compat/browser_compatibility_types.d.ts.map +1 -1
  9. package/dist/commonjs/compat/browser_compatibility_types.js +0 -1
  10. package/dist/commonjs/compat/browser_detection.js +1 -1
  11. package/dist/commonjs/compat/event_listeners.d.ts.map +1 -1
  12. package/dist/commonjs/compat/event_listeners.js +2 -4
  13. package/dist/commonjs/compat/has_mse_in_worker.d.ts.map +1 -1
  14. package/dist/commonjs/core/cmcd/cmcd_data_builder.d.ts.map +1 -1
  15. package/dist/commonjs/core/cmcd/cmcd_data_builder.js +1 -2
  16. package/dist/commonjs/core/main/worker/send_message.d.ts.map +1 -1
  17. package/dist/commonjs/core/main/worker/send_message.js +0 -1
  18. package/dist/commonjs/core/main/worker/worker_main.js +1 -1
  19. package/dist/commonjs/core/stream/adaptation/adaptation_stream.d.ts.map +1 -1
  20. package/dist/commonjs/core/stream/adaptation/adaptation_stream.js +4 -8
  21. package/dist/commonjs/core/stream/period/period_stream.js +1 -3
  22. package/dist/commonjs/core/stream/period/utils/get_adaptation_switch_strategy.js +1 -2
  23. package/dist/commonjs/experimental/tools/mediaCapabilitiesProber/api/index.d.ts.map +1 -1
  24. package/dist/commonjs/main_thread/api/public_api.js +4 -4
  25. package/dist/commonjs/main_thread/decrypt/clear_on_stop.d.ts.map +1 -1
  26. package/dist/commonjs/main_thread/decrypt/clear_on_stop.js +60 -14
  27. package/dist/commonjs/main_thread/decrypt/content_decryptor.d.ts.map +1 -1
  28. package/dist/commonjs/main_thread/decrypt/content_decryptor.js +21 -9
  29. package/dist/commonjs/main_thread/decrypt/dispose_decryption_resources.d.ts.map +1 -1
  30. package/dist/commonjs/main_thread/decrypt/dispose_decryption_resources.js +2 -18
  31. package/dist/commonjs/main_thread/decrypt/find_key_system.d.ts.map +1 -1
  32. package/dist/commonjs/main_thread/decrypt/find_key_system.js +134 -68
  33. package/dist/commonjs/main_thread/decrypt/get_key_system_configuration.js +2 -2
  34. package/dist/commonjs/main_thread/decrypt/get_media_keys.js +5 -3
  35. package/dist/commonjs/main_thread/decrypt/init_media_keys.d.ts.map +1 -1
  36. package/dist/commonjs/main_thread/decrypt/init_media_keys.js +2 -2
  37. package/dist/{es2017/main_thread/decrypt/utils/media_keys_infos_store.d.ts → commonjs/main_thread/decrypt/utils/media_keys_attacher.d.ts} +31 -9
  38. package/dist/commonjs/main_thread/decrypt/utils/media_keys_attacher.d.ts.map +1 -0
  39. package/dist/commonjs/main_thread/decrypt/utils/media_keys_attacher.js +282 -0
  40. package/dist/commonjs/main_thread/init/utils/rebuffering_controller.d.ts.map +1 -1
  41. package/dist/commonjs/main_thread/init/utils/rebuffering_controller.js +20 -9
  42. package/dist/commonjs/main_thread/text_displayer/html/text_track_cues_store.js +1 -1
  43. package/dist/commonjs/main_thread/tracks_store/track_dispatcher.d.ts.map +1 -1
  44. package/dist/commonjs/main_thread/tracks_store/track_dispatcher.js +3 -4
  45. package/dist/commonjs/main_thread/tracks_store/tracks_store.d.ts.map +1 -1
  46. package/dist/commonjs/main_thread/tracks_store/tracks_store.js +1 -1
  47. package/dist/commonjs/manifest/classes/representation.d.ts +15 -1
  48. package/dist/commonjs/manifest/classes/representation.d.ts.map +1 -1
  49. package/dist/commonjs/manifest/classes/representation.js +17 -0
  50. package/dist/commonjs/manifest/utils.d.ts +15 -0
  51. package/dist/commonjs/manifest/utils.d.ts.map +1 -1
  52. package/dist/commonjs/manifest/utils.js +28 -5
  53. package/dist/commonjs/parsers/manifest/dash/common/parse_representations.js +2 -2
  54. package/dist/commonjs/playback_observer/media_element_playback_observer.js +1 -1
  55. package/dist/commonjs/public_types.d.ts +44 -0
  56. package/dist/commonjs/public_types.d.ts.map +1 -1
  57. package/dist/commonjs/utils/flat_map.d.ts +2 -2
  58. package/dist/commonjs/utils/flat_map.js +2 -2
  59. package/dist/commonjs/utils/url-utils.d.ts.map +1 -1
  60. package/dist/commonjs/utils/url-utils.js +11 -10
  61. package/dist/commonjs/utils/xml-parser.d.ts.map +1 -1
  62. package/dist/commonjs/utils/xml-parser.js +10 -8
  63. package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.d.ts +1 -1
  64. package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
  65. package/dist/es2017/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
  66. package/dist/es2017/__GENERATED_CODE/embedded_worker.js +1 -1
  67. package/dist/es2017/compat/browser_compatibility_types.d.ts +7 -2
  68. package/dist/es2017/compat/browser_compatibility_types.d.ts.map +1 -1
  69. package/dist/es2017/compat/browser_compatibility_types.js +0 -1
  70. package/dist/es2017/compat/browser_detection.js +1 -1
  71. package/dist/es2017/compat/event_listeners.d.ts.map +1 -1
  72. package/dist/es2017/compat/event_listeners.js +2 -4
  73. package/dist/es2017/compat/has_mse_in_worker.d.ts.map +1 -1
  74. package/dist/es2017/core/cmcd/cmcd_data_builder.d.ts.map +1 -1
  75. package/dist/es2017/core/cmcd/cmcd_data_builder.js +1 -2
  76. package/dist/es2017/core/main/worker/send_message.d.ts.map +1 -1
  77. package/dist/es2017/core/main/worker/send_message.js +0 -1
  78. package/dist/es2017/core/main/worker/worker_main.js +1 -1
  79. package/dist/es2017/core/stream/adaptation/adaptation_stream.d.ts.map +1 -1
  80. package/dist/es2017/core/stream/adaptation/adaptation_stream.js +4 -6
  81. package/dist/es2017/core/stream/period/period_stream.js +1 -3
  82. package/dist/es2017/core/stream/period/utils/get_adaptation_switch_strategy.js +1 -2
  83. package/dist/es2017/experimental/tools/mediaCapabilitiesProber/api/index.d.ts.map +1 -1
  84. package/dist/es2017/main_thread/api/public_api.js +4 -4
  85. package/dist/es2017/main_thread/decrypt/clear_on_stop.d.ts.map +1 -1
  86. package/dist/es2017/main_thread/decrypt/clear_on_stop.js +3 -3
  87. package/dist/es2017/main_thread/decrypt/content_decryptor.d.ts.map +1 -1
  88. package/dist/es2017/main_thread/decrypt/content_decryptor.js +21 -9
  89. package/dist/es2017/main_thread/decrypt/dispose_decryption_resources.d.ts.map +1 -1
  90. package/dist/es2017/main_thread/decrypt/dispose_decryption_resources.js +2 -12
  91. package/dist/es2017/main_thread/decrypt/find_key_system.d.ts.map +1 -1
  92. package/dist/es2017/main_thread/decrypt/find_key_system.js +102 -56
  93. package/dist/es2017/main_thread/decrypt/get_key_system_configuration.js +2 -2
  94. package/dist/es2017/main_thread/decrypt/get_media_keys.js +2 -2
  95. package/dist/es2017/main_thread/decrypt/init_media_keys.d.ts.map +1 -1
  96. package/dist/es2017/main_thread/decrypt/init_media_keys.js +2 -2
  97. package/dist/{commonjs/main_thread/decrypt/utils/media_keys_infos_store.d.ts → es2017/main_thread/decrypt/utils/media_keys_attacher.d.ts} +31 -9
  98. package/dist/es2017/main_thread/decrypt/utils/media_keys_attacher.d.ts.map +1 -0
  99. package/dist/es2017/main_thread/decrypt/utils/media_keys_attacher.js +180 -0
  100. package/dist/es2017/main_thread/init/utils/rebuffering_controller.d.ts.map +1 -1
  101. package/dist/es2017/main_thread/init/utils/rebuffering_controller.js +20 -9
  102. package/dist/es2017/main_thread/text_displayer/html/text_track_cues_store.js +1 -1
  103. package/dist/es2017/main_thread/tracks_store/track_dispatcher.d.ts.map +1 -1
  104. package/dist/es2017/main_thread/tracks_store/track_dispatcher.js +3 -4
  105. package/dist/es2017/main_thread/tracks_store/tracks_store.d.ts.map +1 -1
  106. package/dist/es2017/main_thread/tracks_store/tracks_store.js +2 -2
  107. package/dist/es2017/manifest/classes/representation.d.ts +15 -1
  108. package/dist/es2017/manifest/classes/representation.d.ts.map +1 -1
  109. package/dist/es2017/manifest/classes/representation.js +17 -0
  110. package/dist/es2017/manifest/utils.d.ts +15 -0
  111. package/dist/es2017/manifest/utils.d.ts.map +1 -1
  112. package/dist/es2017/manifest/utils.js +27 -5
  113. package/dist/es2017/parsers/manifest/dash/common/parse_representations.js +2 -2
  114. package/dist/es2017/playback_observer/media_element_playback_observer.js +1 -1
  115. package/dist/es2017/public_types.d.ts +44 -0
  116. package/dist/es2017/public_types.d.ts.map +1 -1
  117. package/dist/es2017/utils/flat_map.d.ts +2 -2
  118. package/dist/es2017/utils/flat_map.js +2 -2
  119. package/dist/es2017/utils/url-utils.d.ts.map +1 -1
  120. package/dist/es2017/utils/url-utils.js +11 -10
  121. package/dist/es2017/utils/xml-parser.d.ts.map +1 -1
  122. package/dist/es2017/utils/xml-parser.js +10 -8
  123. package/dist/rx-player.js +505 -372
  124. package/dist/rx-player.min.js +18 -18
  125. package/dist/worker.js +6 -6
  126. package/package.json +21 -19
  127. package/src/__GENERATED_CODE/embedded_worker.ts +1 -1
  128. package/src/compat/browser_compatibility_types.ts +22 -4
  129. package/src/compat/browser_detection.ts +1 -1
  130. package/src/compat/event_listeners.ts +2 -4
  131. package/src/compat/has_mse_in_worker.ts +1 -1
  132. package/src/core/cmcd/cmcd_data_builder.ts +1 -4
  133. package/src/core/main/worker/send_message.ts +4 -2
  134. package/src/core/main/worker/worker_main.ts +1 -1
  135. package/src/core/stream/adaptation/adaptation_stream.ts +4 -7
  136. package/src/core/stream/period/period_stream.ts +3 -3
  137. package/src/core/stream/period/utils/get_adaptation_switch_strategy.ts +1 -2
  138. package/src/main_thread/api/public_api.ts +4 -4
  139. package/src/main_thread/decrypt/__tests__/__global__/media_key_system_access.test.ts +239 -6
  140. package/src/main_thread/decrypt/__tests__/find_key_system.test.ts +325 -0
  141. package/src/main_thread/decrypt/clear_on_stop.ts +3 -3
  142. package/src/main_thread/decrypt/content_decryptor.ts +26 -8
  143. package/src/main_thread/decrypt/dispose_decryption_resources.ts +2 -13
  144. package/src/main_thread/decrypt/find_key_system.ts +120 -81
  145. package/src/main_thread/decrypt/get_key_system_configuration.ts +2 -2
  146. package/src/main_thread/decrypt/get_media_keys.ts +2 -2
  147. package/src/main_thread/decrypt/init_media_keys.ts +2 -2
  148. package/src/main_thread/decrypt/utils/media_keys_attacher.ts +284 -0
  149. package/src/main_thread/init/utils/rebuffering_controller.ts +20 -10
  150. package/src/main_thread/text_displayer/html/text_track_cues_store.ts +1 -1
  151. package/src/main_thread/tracks_store/track_dispatcher.ts +3 -6
  152. package/src/main_thread/tracks_store/tracks_store.ts +2 -1
  153. package/src/manifest/classes/representation.ts +18 -1
  154. package/src/manifest/utils.ts +30 -9
  155. package/src/parsers/manifest/dash/common/parse_representations.ts +2 -2
  156. package/src/playback_observer/media_element_playback_observer.ts +1 -1
  157. package/src/public_types.ts +45 -0
  158. package/src/utils/__tests__/flat_map.test.ts +7 -20
  159. package/src/utils/flat_map.ts +2 -2
  160. package/src/utils/url-utils.ts +11 -10
  161. package/src/utils/xml-parser.ts +13 -8
  162. package/vitest.config.mjs +9 -23
  163. package/dist/commonjs/main_thread/decrypt/attach_media_keys.d.ts +0 -60
  164. package/dist/commonjs/main_thread/decrypt/attach_media_keys.d.ts.map +0 -1
  165. package/dist/commonjs/main_thread/decrypt/attach_media_keys.js +0 -124
  166. package/dist/commonjs/main_thread/decrypt/utils/media_keys_infos_store.d.ts.map +0 -1
  167. package/dist/commonjs/main_thread/decrypt/utils/media_keys_infos_store.js +0 -45
  168. package/dist/es2017/main_thread/decrypt/attach_media_keys.d.ts +0 -60
  169. package/dist/es2017/main_thread/decrypt/attach_media_keys.d.ts.map +0 -1
  170. package/dist/es2017/main_thread/decrypt/attach_media_keys.js +0 -73
  171. package/dist/es2017/main_thread/decrypt/utils/media_keys_infos_store.d.ts.map +0 -1
  172. package/dist/es2017/main_thread/decrypt/utils/media_keys_infos_store.js +0 -43
  173. package/src/main_thread/decrypt/attach_media_keys.ts +0 -125
  174. package/src/main_thread/decrypt/utils/media_keys_infos_store.ts +0 -88
@@ -0,0 +1,325 @@
1
+ import type { MockInstance } from "vitest";
2
+ import { describe, beforeEach, it, expect, vi } from "vitest";
3
+ import eme from "../../../compat/eme";
4
+ import type { IKeySystemOption } from "../../../public_types";
5
+ import TaskCanceller from "../../../utils/task_canceller";
6
+ import getMediaKeySystemAccess from "../find_key_system";
7
+ import LoadedSessionsStore from "../utils/loaded_sessions_store";
8
+ import mediaKeysAttacher from "../utils/media_keys_attacher";
9
+
10
+ describe("find_key_systems - ", () => {
11
+ let requestMediaKeySystemAccessMock: MockInstance;
12
+
13
+ beforeEach(() => {
14
+ vi.resetModules();
15
+ vi.restoreAllMocks();
16
+ requestMediaKeySystemAccessMock = vi.spyOn(eme, "requestMediaKeySystemAccess");
17
+ });
18
+
19
+ const baseEmeConfiguration: MediaKeySystemConfiguration = {
20
+ initDataTypes: ["cenc"],
21
+ videoCapabilities: [
22
+ {
23
+ contentType: 'video/mp4;codecs="avc1.4d401e"',
24
+ robustness: "HW_SECURE_ALL",
25
+ },
26
+ {
27
+ contentType: 'video/mp4;codecs="avc1.42e01e"',
28
+ robustness: "HW_SECURE_ALL",
29
+ },
30
+ {
31
+ contentType: 'video/mp4;codecs="hvc1.1.6.L93.B0"',
32
+ robustness: "HW_SECURE_ALL",
33
+ },
34
+ {
35
+ contentType: 'video/webm;codecs="vp8"',
36
+ robustness: "HW_SECURE_ALL",
37
+ },
38
+ {
39
+ contentType: 'video/mp4;codecs="avc1.4d401e"',
40
+ robustness: "HW_SECURE_DECODE",
41
+ },
42
+ {
43
+ contentType: 'video/mp4;codecs="avc1.42e01e"',
44
+ robustness: "HW_SECURE_DECODE",
45
+ },
46
+ {
47
+ contentType: 'video/mp4;codecs="hvc1.1.6.L93.B0"',
48
+ robustness: "HW_SECURE_DECODE",
49
+ },
50
+ {
51
+ contentType: 'video/webm;codecs="vp8"',
52
+ robustness: "HW_SECURE_DECODE",
53
+ },
54
+ {
55
+ contentType: 'video/mp4;codecs="avc1.4d401e"',
56
+ robustness: "HW_SECURE_CRYPTO",
57
+ },
58
+ {
59
+ contentType: 'video/mp4;codecs="avc1.42e01e"',
60
+ robustness: "HW_SECURE_CRYPTO",
61
+ },
62
+ {
63
+ contentType: 'video/mp4;codecs="hvc1.1.6.L93.B0"',
64
+ robustness: "HW_SECURE_CRYPTO",
65
+ },
66
+ {
67
+ contentType: 'video/webm;codecs="vp8"',
68
+ robustness: "HW_SECURE_CRYPTO",
69
+ },
70
+ {
71
+ contentType: 'video/mp4;codecs="avc1.4d401e"',
72
+ robustness: "SW_SECURE_DECODE",
73
+ },
74
+ {
75
+ contentType: 'video/mp4;codecs="avc1.42e01e"',
76
+ robustness: "SW_SECURE_DECODE",
77
+ },
78
+ {
79
+ contentType: 'video/mp4;codecs="hvc1.1.6.L93.B0"',
80
+ robustness: "SW_SECURE_DECODE",
81
+ },
82
+ {
83
+ contentType: 'video/webm;codecs="vp8"',
84
+ robustness: "SW_SECURE_DECODE",
85
+ },
86
+ {
87
+ contentType: 'video/mp4;codecs="avc1.4d401e"',
88
+ robustness: "SW_SECURE_CRYPTO",
89
+ },
90
+ {
91
+ contentType: 'video/mp4;codecs="avc1.42e01e"',
92
+ robustness: "SW_SECURE_CRYPTO",
93
+ },
94
+ {
95
+ contentType: 'video/mp4;codecs="hvc1.1.6.L93.B0"',
96
+ robustness: "SW_SECURE_CRYPTO",
97
+ },
98
+ {
99
+ contentType: 'video/webm;codecs="vp8"',
100
+ robustness: "SW_SECURE_CRYPTO",
101
+ },
102
+ ],
103
+ audioCapabilities: [
104
+ {
105
+ contentType: 'audio/mp4;codecs="mp4a.40.2"',
106
+ robustness: "HW_SECURE_ALL",
107
+ },
108
+ {
109
+ contentType: "audio/webm;codecs=opus",
110
+ robustness: "HW_SECURE_ALL",
111
+ },
112
+ {
113
+ contentType: 'audio/mp4;codecs="mp4a.40.2"',
114
+ robustness: "HW_SECURE_DECODE",
115
+ },
116
+ {
117
+ contentType: "audio/webm;codecs=opus",
118
+ robustness: "HW_SECURE_DECODE",
119
+ },
120
+ {
121
+ contentType: 'audio/mp4;codecs="mp4a.40.2"',
122
+ robustness: "HW_SECURE_CRYPTO",
123
+ },
124
+ {
125
+ contentType: "audio/webm;codecs=opus",
126
+ robustness: "HW_SECURE_CRYPTO",
127
+ },
128
+ {
129
+ contentType: 'audio/mp4;codecs="mp4a.40.2"',
130
+ robustness: "SW_SECURE_DECODE",
131
+ },
132
+ {
133
+ contentType: "audio/webm;codecs=opus",
134
+ robustness: "SW_SECURE_DECODE",
135
+ },
136
+ {
137
+ contentType: 'audio/mp4;codecs="mp4a.40.2"',
138
+ robustness: "SW_SECURE_CRYPTO",
139
+ },
140
+ {
141
+ contentType: "audio/webm;codecs=opus",
142
+ robustness: "SW_SECURE_CRYPTO",
143
+ },
144
+ ],
145
+ distinctiveIdentifier: "optional",
146
+ persistentState: "optional",
147
+ sessionTypes: ["temporary"],
148
+ };
149
+
150
+ it("should create a media key the first time and then reuse the previous one if it's the same configuration", async () => {
151
+ requestMediaKeySystemAccessMock.mockImplementation(() => {
152
+ return {
153
+ keySystem: "com.widevine.alpha",
154
+ createMediaKeys: () => ({
155
+ createSession: () => ({
156
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
157
+ generateRequest: () => {},
158
+ }),
159
+ }),
160
+ getConfiguration: () => {
161
+ return baseEmeConfiguration;
162
+ },
163
+ };
164
+ });
165
+ const mediaElement = document.createElement("video");
166
+ const keySystemOptionsA: IKeySystemOption[] = [
167
+ {
168
+ type: "com.widevine.alpha",
169
+ getLicense: () => null,
170
+ persistentState: "optional",
171
+ },
172
+ ];
173
+
174
+ const taskCanceller = new TaskCanceller();
175
+ const event1 = await getMediaKeySystemAccess(
176
+ mediaElement,
177
+ keySystemOptionsA,
178
+ taskCanceller.signal,
179
+ );
180
+ expect(event1.type).toBe("create-media-key-system-access");
181
+
182
+ // create the mediaKeys and add it to the cache
183
+ const mediaKeys = await event1.value.mediaKeySystemAccess.createMediaKeys();
184
+ await mediaKeysAttacher.attach(mediaElement, {
185
+ keySystemOptions: keySystemOptionsA[0],
186
+ emeImplementation: eme,
187
+ askedConfiguration: baseEmeConfiguration,
188
+ mediaKeys,
189
+ mediaKeySystemAccess: event1.value.mediaKeySystemAccess,
190
+ loadedSessionsStore: new LoadedSessionsStore(mediaKeys),
191
+ });
192
+
193
+ const event2 = await getMediaKeySystemAccess(
194
+ mediaElement,
195
+ keySystemOptionsA,
196
+ taskCanceller.signal,
197
+ );
198
+ expect(event2.type).toBe("reuse-media-key-system-access");
199
+ });
200
+
201
+ it("should create a media key the first time and then create another one if the previous is not compatible.", async () => {
202
+ requestMediaKeySystemAccessMock.mockImplementation(() => {
203
+ return {
204
+ keySystem: "com.widevine.alpha",
205
+ createMediaKeys: () => ({
206
+ createSession: () => ({
207
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
208
+ generateRequest: () => {},
209
+ }),
210
+ }),
211
+ getConfiguration: () => {
212
+ return baseEmeConfiguration;
213
+ },
214
+ };
215
+ });
216
+ const mediaElement = document.createElement("video");
217
+ const keySystemOptionsA: IKeySystemOption[] = [
218
+ {
219
+ type: "com.widevine.alpha",
220
+ getLicense: () => null,
221
+ persistentState: "optional",
222
+ },
223
+ ];
224
+
225
+ const taskCanceller = new TaskCanceller();
226
+ const event1 = await getMediaKeySystemAccess(
227
+ mediaElement,
228
+ keySystemOptionsA,
229
+ taskCanceller.signal,
230
+ );
231
+ expect(event1.type).toBe("create-media-key-system-access");
232
+
233
+ // create the mediaKeys and add it to the cache
234
+ const mediaKeys = await event1.value.mediaKeySystemAccess.createMediaKeys();
235
+ await mediaKeysAttacher.attach(mediaElement, {
236
+ keySystemOptions: keySystemOptionsA[0],
237
+ emeImplementation: eme,
238
+ askedConfiguration: baseEmeConfiguration,
239
+ mediaKeys,
240
+ mediaKeySystemAccess: event1.value.mediaKeySystemAccess,
241
+ loadedSessionsStore: new LoadedSessionsStore(mediaKeys),
242
+ });
243
+
244
+ const keySystemOptionsB: IKeySystemOption[] = [
245
+ {
246
+ type: "com.widevine.alpha",
247
+ getLicense: () => null,
248
+ persistentState: "required", // persistentState differs from configuration A.
249
+ },
250
+ ];
251
+
252
+ const event2 = await getMediaKeySystemAccess(
253
+ mediaElement,
254
+ keySystemOptionsB,
255
+ taskCanceller.signal,
256
+ );
257
+ expect(event2.type).toBe("create-media-key-system-access");
258
+ });
259
+
260
+ it("should create a media key the first time and then reuse the previous one if it's a different configuration but it's a compatible configuration.", async () => {
261
+ requestMediaKeySystemAccessMock.mockImplementation(() => {
262
+ return {
263
+ keySystem: "com.widevine.alpha",
264
+ createMediaKeys: () => ({
265
+ createSession: () => ({
266
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
267
+ generateRequest: () => {},
268
+ }),
269
+ }),
270
+ getConfiguration: () => {
271
+ return baseEmeConfiguration;
272
+ },
273
+ };
274
+ });
275
+ const mediaElement = document.createElement("video");
276
+ const keySystemOptionsA: IKeySystemOption[] = [
277
+ {
278
+ type: "com.widevine.alpha",
279
+ getLicense: () => null,
280
+ videoCapabilitiesConfig: {
281
+ type: "contentType",
282
+ value: ['video/mp4;codecs="avc1.4d401e', 'video/mp4;codecs="hvc1.1.6.L93.B0"'],
283
+ },
284
+ },
285
+ ];
286
+
287
+ const taskCanceller = new TaskCanceller();
288
+ const event1 = await getMediaKeySystemAccess(
289
+ mediaElement,
290
+ keySystemOptionsA,
291
+ taskCanceller.signal,
292
+ );
293
+ expect(event1.type).toBe("create-media-key-system-access");
294
+
295
+ // create the mediaKeys and add it to the cache
296
+ const mediaKeys = await event1.value.mediaKeySystemAccess.createMediaKeys();
297
+ await mediaKeysAttacher.attach(mediaElement, {
298
+ keySystemOptions: keySystemOptionsA[0],
299
+ emeImplementation: eme,
300
+ askedConfiguration: baseEmeConfiguration,
301
+ mediaKeys,
302
+ mediaKeySystemAccess: event1.value.mediaKeySystemAccess,
303
+ loadedSessionsStore: new LoadedSessionsStore(mediaKeys),
304
+ });
305
+
306
+ const keySystemOptionsB: IKeySystemOption[] = [
307
+ {
308
+ type: "com.widevine.alpha",
309
+ getLicense: () => null,
310
+ videoCapabilitiesConfig: {
311
+ type: "contentType",
312
+ // configB contains only codec "avc1", it's a subset of configA, it should be compatible.
313
+ value: ['video/mp4;codecs="avc1.4d401e'],
314
+ },
315
+ },
316
+ ];
317
+
318
+ const event2 = await getMediaKeySystemAccess(
319
+ mediaElement,
320
+ keySystemOptionsB,
321
+ taskCanceller.signal,
322
+ );
323
+ expect(event2.type).toBe("reuse-media-key-system-access");
324
+ });
325
+ });
@@ -18,7 +18,7 @@ import type { IMediaElement } from "../../compat/browser_compatibility_types";
18
18
  import shouldUnsetMediaKeys from "../../compat/should_unset_media_keys";
19
19
  import log from "../../log";
20
20
  import disposeDecryptionResources from "./dispose_decryption_resources";
21
- import MediaKeysInfosStore from "./utils/media_keys_infos_store";
21
+ import MediaKeysAttacher from "./utils/media_keys_attacher";
22
22
 
23
23
  /**
24
24
  * Clear DRM-related resources that should be cleared when the current content
@@ -26,14 +26,14 @@ import MediaKeysInfosStore from "./utils/media_keys_infos_store";
26
26
  * @param {HTMLMediaElement} mediaElement
27
27
  * @returns {Promise}
28
28
  */
29
- export default function clearOnStop(mediaElement: IMediaElement): Promise<unknown> {
29
+ export default async function clearOnStop(mediaElement: IMediaElement): Promise<unknown> {
30
30
  log.info("DRM: Clearing-up DRM session.");
31
31
  if (shouldUnsetMediaKeys()) {
32
32
  log.info("DRM: disposing current MediaKeys.");
33
33
  return disposeDecryptionResources(mediaElement);
34
34
  }
35
35
 
36
- const currentState = MediaKeysInfosStore.getState(mediaElement);
36
+ const currentState = await MediaKeysAttacher.getAttachedMediaKeysState(mediaElement);
37
37
  if (
38
38
  currentState !== null &&
39
39
  currentState.keySystemOptions.closeSessionsOnStop === true
@@ -30,7 +30,6 @@ import isNullOrUndefined from "../../utils/is_null_or_undefined";
30
30
  import { objectValues } from "../../utils/object_values";
31
31
  import { bytesToHex } from "../../utils/string_parsing";
32
32
  import TaskCanceller from "../../utils/task_canceller";
33
- import attachMediaKeys from "./attach_media_keys";
34
33
  import createOrLoadSession from "./create_or_load_session";
35
34
  import type { ICodecSupportList } from "./find_key_system";
36
35
  import type { IMediaKeysInfos } from "./get_media_keys";
@@ -57,6 +56,7 @@ import {
57
56
  areSomeKeyIdsContainedIn,
58
57
  } from "./utils/key_id_comparison";
59
58
  import type KeySessionRecord from "./utils/key_session_record";
59
+ import MediaKeysAttacher from "./utils/media_keys_attacher";
60
60
 
61
61
  /**
62
62
  * Module communicating with the Content Decryption Module (or CDM) to be able
@@ -287,8 +287,12 @@ export default class ContentDecryptor extends EventEmitter<IContentDecryptorEven
287
287
  };
288
288
 
289
289
  log.debug("DRM: Attaching current MediaKeys");
290
- attachMediaKeys(mediaElement, stateToAttach, this._canceller.signal)
290
+ MediaKeysAttacher.attach(mediaElement, stateToAttach)
291
291
  .then(async () => {
292
+ if (this._isStopped()) {
293
+ // We might be stopped since then
294
+ return;
295
+ }
292
296
  this._stateData.isMediaKeysAttached = MediaKeyAttachmentStatus.Attached;
293
297
 
294
298
  const { serverCertificate } = options;
@@ -526,13 +530,14 @@ export default class ContentDecryptor extends EventEmitter<IContentDecryptorEven
526
530
  this._lockInitDataQueue();
527
531
 
528
532
  let wantedSessionType: MediaKeySessionType;
529
- if (isNullOrUndefined(options.persistentLicenseConfig)) {
530
- wantedSessionType = "temporary";
531
- } else if (!canCreatePersistentSession(mediaKeySystemAccess)) {
532
- log.warn('DRM: Cannot create "persistent-license" session: not supported');
533
- wantedSessionType = "temporary";
534
- } else {
533
+ if (
534
+ canCreatePersistentSession(mediaKeySystemAccess) &&
535
+ (!isNullOrUndefined(options.persistentLicenseConfig) ||
536
+ !canCreateTemporarySession(mediaKeySystemAccess))
537
+ ) {
535
538
  wantedSessionType = "persistent-license";
539
+ } else {
540
+ wantedSessionType = "temporary";
536
541
  }
537
542
 
538
543
  const {
@@ -993,6 +998,19 @@ function canCreatePersistentSession(
993
998
  return sessionTypes !== undefined && arrayIncludes(sessionTypes, "persistent-license");
994
999
  }
995
1000
 
1001
+ /**
1002
+ * Returns `true` if the given MediaKeySystemAccess can create
1003
+ * "temporary" MediaKeySessions.
1004
+ * @param {MediaKeySystemAccess} mediaKeySystemAccess
1005
+ * @returns {Boolean}
1006
+ */
1007
+ function canCreateTemporarySession(
1008
+ mediaKeySystemAccess: MediaKeySystemAccess | ICustomMediaKeySystemAccess,
1009
+ ): boolean {
1010
+ const { sessionTypes } = mediaKeySystemAccess.getConfiguration();
1011
+ return sessionTypes !== undefined && arrayIncludes(sessionTypes, "temporary");
1012
+ }
1013
+
996
1014
  /**
997
1015
  * Return the list of key IDs present in the `expectedKeyIds` array
998
1016
  * but that are not present in `actualKeyIds`.
@@ -15,9 +15,7 @@
15
15
  */
16
16
 
17
17
  import type { IMediaElement } from "../../compat/browser_compatibility_types";
18
- import { setMediaKeys } from "../../compat/eme/set_media_keys";
19
- import log from "../../log";
20
- import MediaKeysInfosStore from "./utils/media_keys_infos_store";
18
+ import MediaKeysAttacher from "./utils/media_keys_attacher";
21
19
 
22
20
  /**
23
21
  * Free up all ressources taken by the content decryption logic.
@@ -27,14 +25,5 @@ import MediaKeysInfosStore from "./utils/media_keys_infos_store";
27
25
  export default async function disposeDecryptionResources(
28
26
  mediaElement: IMediaElement,
29
27
  ): Promise<unknown> {
30
- const currentState = MediaKeysInfosStore.getState(mediaElement);
31
- if (currentState === null) {
32
- return undefined;
33
- }
34
-
35
- log.info("DRM: Disposing of the current MediaKeys");
36
- const { loadedSessionsStore } = currentState;
37
- MediaKeysInfosStore.clearState(mediaElement);
38
- await loadedSessionsStore.closeAllSessions();
39
- return setMediaKeys(currentState.emeImplementation, mediaElement, null);
28
+ return MediaKeysAttacher.clearMediaKeys(mediaElement);
40
29
  }