shaka-player 3.3.4 → 4.0.1

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 (201) hide show
  1. package/.github/config.yml +1 -0
  2. package/.github/workflows/build-and-test.yaml +0 -1
  3. package/.github/workflows/demo-version-index.yaml +8 -0
  4. package/.github/workflows/release-please.yaml +19 -3
  5. package/.github/workflows/selenium-lab-tests.yaml +0 -1
  6. package/.github/workflows/sync-labels.yaml +33 -0
  7. package/.github/workflows/update-issues.yaml +29 -0
  8. package/.github/workflows/validate-pr-title.yaml +35 -0
  9. package/AUTHORS +1 -0
  10. package/CHANGELOG.md +209 -28
  11. package/CONTRIBUTORS +1 -0
  12. package/README.md +10 -7
  13. package/app-engine/demo-version-index/README.md +3 -3
  14. package/app-engine/demo-version-index/app.yaml +27 -1
  15. package/app-engine/demo-version-index/generate.py +164 -0
  16. package/app-engine/demo-version-index/main.py +4 -155
  17. package/app-engine/demo-version-index/requirements.txt +0 -1
  18. package/build/README.md +2 -2
  19. package/build/compiler.py +1 -1
  20. package/build/generateTsDefs.py +0 -2
  21. package/build/misspellings.txt +1 -0
  22. package/build/shaka-lab.yaml +0 -2
  23. package/build/test.py +7 -1
  24. package/build/types/core +0 -1
  25. package/build/types/polyfill +0 -3
  26. package/demo/common/asset.js +17 -1
  27. package/demo/common/assets.js +29 -0
  28. package/demo/common/message_ids.js +6 -3
  29. package/demo/config.js +10 -11
  30. package/demo/custom.js +39 -0
  31. package/demo/demo_utils.js +0 -1
  32. package/demo/locales/en.json +6 -3
  33. package/demo/locales/source.json +22 -10
  34. package/demo/main.js +9 -6
  35. package/demo/search.js +2 -1
  36. package/dist/controls.css +1 -1
  37. package/dist/demo.compiled.debug.js +71 -64
  38. package/dist/demo.compiled.debug.map +3 -3
  39. package/dist/demo.compiled.js +71 -64
  40. package/dist/demo.compiled.map +3 -3
  41. package/dist/demo.css +1 -1
  42. package/dist/demo.css.map +1 -1
  43. package/dist/deps.js +16 -20
  44. package/dist/locales.js +33 -31
  45. package/dist/receiver.compiled.debug.js +32 -28
  46. package/dist/receiver.compiled.debug.map +3 -3
  47. package/dist/receiver.compiled.js +32 -28
  48. package/dist/receiver.compiled.map +3 -3
  49. package/dist/shaka-player.compiled.d.ts +78 -82
  50. package/dist/shaka-player.compiled.debug.d.ts +78 -82
  51. package/dist/shaka-player.compiled.debug.externs.js +127 -126
  52. package/dist/shaka-player.compiled.debug.js +471 -523
  53. package/dist/shaka-player.compiled.debug.map +4 -4
  54. package/dist/shaka-player.compiled.externs.js +127 -126
  55. package/dist/shaka-player.compiled.js +844 -858
  56. package/dist/shaka-player.compiled.map +4 -4
  57. package/dist/shaka-player.ui.d.ts +80 -82
  58. package/dist/shaka-player.ui.debug.d.ts +80 -82
  59. package/dist/shaka-player.ui.debug.externs.js +135 -126
  60. package/dist/shaka-player.ui.debug.js +531 -581
  61. package/dist/shaka-player.ui.debug.map +4 -4
  62. package/dist/shaka-player.ui.externs.js +135 -126
  63. package/dist/shaka-player.ui.js +991 -1001
  64. package/dist/shaka-player.ui.map +4 -4
  65. package/docs/tutorials/config.md +0 -2
  66. package/docs/tutorials/drm-config.md +5 -0
  67. package/docs/tutorials/fairplay.md +7 -22
  68. package/docs/tutorials/faq.md +0 -11
  69. package/docs/tutorials/index.json +2 -8
  70. package/docs/tutorials/plugins.md +1 -3
  71. package/docs/tutorials/upgrade.md +85 -11
  72. package/externs/polyfill.js +15 -0
  73. package/externs/shaka/manifest.js +5 -1
  74. package/externs/shaka/net.js +12 -0
  75. package/externs/shaka/offline.js +5 -1
  76. package/externs/shaka/player.js +39 -21
  77. package/externs/shaka/text.js +12 -12
  78. package/externs/sourcebuffer.js +15 -0
  79. package/karma.conf.js +4 -0
  80. package/lib/ads/client_side_ad.js +13 -2
  81. package/lib/ads/client_side_ad_manager.js +22 -4
  82. package/lib/cast/cast_utils.js +0 -1
  83. package/lib/dash/content_protection.js +85 -5
  84. package/lib/dash/dash_parser.js +3 -3
  85. package/lib/hls/hls_parser.js +391 -747
  86. package/lib/hls/manifest_text_parser.js +2 -3
  87. package/lib/media/drm_engine.js +102 -37
  88. package/lib/media/gap_jumping_controller.js +10 -45
  89. package/lib/media/media_source_engine.js +157 -31
  90. package/lib/media/playhead.js +2 -5
  91. package/lib/media/presentation_timeline.js +1 -2
  92. package/lib/media/segment_index.js +13 -46
  93. package/lib/media/segment_reference.js +47 -1
  94. package/lib/media/streaming_engine.js +28 -11
  95. package/lib/media/time_ranges_utils.js +4 -9
  96. package/lib/net/networking_engine.js +3 -0
  97. package/lib/offline/indexeddb/storage_mechanism.js +4 -2
  98. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  99. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  100. package/lib/offline/manifest_converter.js +1 -0
  101. package/lib/offline/storage.js +100 -132
  102. package/lib/player.js +181 -307
  103. package/lib/polyfill/media_capabilities.js +12 -6
  104. package/lib/polyfill/mediasource.js +0 -28
  105. package/lib/polyfill/patchedmediakeys_nop.js +2 -0
  106. package/lib/polyfill/patchedmediakeys_webkit.js +2 -0
  107. package/lib/text/cue.js +0 -6
  108. package/lib/text/lrc_text_parser.js +8 -0
  109. package/lib/text/mp4_ttml_parser.js +8 -0
  110. package/lib/text/mp4_vtt_parser.js +8 -0
  111. package/lib/text/sbv_text_parser.js +8 -0
  112. package/lib/text/simple_text_displayer.js +1 -7
  113. package/lib/text/srt_text_parser.js +8 -0
  114. package/lib/text/ssa_text_parser.js +8 -0
  115. package/lib/text/text_engine.js +19 -3
  116. package/lib/text/ttml_text_parser.js +8 -0
  117. package/lib/text/ui_text_displayer.js +1 -7
  118. package/lib/text/vtt_text_parser.js +27 -5
  119. package/lib/text/web_vtt_generator.js +1 -7
  120. package/lib/util/config_utils.js +25 -0
  121. package/lib/util/error.js +16 -13
  122. package/lib/util/fairplay_utils.js +109 -0
  123. package/lib/util/functional.js +0 -42
  124. package/lib/util/manifest_parser_utils.js +1 -1
  125. package/lib/util/mime_utils.js +50 -1
  126. package/lib/util/periods.js +5 -4
  127. package/lib/util/platform.js +45 -0
  128. package/lib/util/player_configuration.js +26 -20
  129. package/lib/util/pssh.js +23 -4
  130. package/lib/util/stream_utils.js +96 -24
  131. package/lib/util/uint8array_utils.js +0 -16
  132. package/lib/util/xml_utils.js +1 -1
  133. package/package.json +4 -1
  134. package/roadmap.md +19 -19
  135. package/shaka-player.uncompiled.js +0 -3
  136. package/test/cast/cast_utils_unit.js +1 -0
  137. package/test/dash/dash_parser_content_protection_unit.js +44 -0
  138. package/test/dash/dash_parser_manifest_unit.js +0 -24
  139. package/test/dash/dash_parser_segment_template_unit.js +3 -4
  140. package/test/demo/demo_unit.js +2 -1
  141. package/test/hls/hls_live_unit.js +121 -220
  142. package/test/hls/hls_parser_unit.js +515 -432
  143. package/test/hls/manifest_text_parser_unit.js +19 -0
  144. package/test/media/drm_engine_unit.js +86 -120
  145. package/test/media/media_source_engine_integration.js +26 -3
  146. package/test/media/media_source_engine_unit.js +7 -6
  147. package/test/media/playhead_unit.js +27 -191
  148. package/test/media/segment_index_unit.js +15 -25
  149. package/test/media/streaming_engine_integration.js +4 -39
  150. package/test/media/streaming_engine_unit.js +3 -2
  151. package/test/media/time_ranges_utils_unit.js +0 -5
  152. package/test/offline/indexeddb_storage_unit.js +1 -1
  153. package/test/offline/manifest_convert_unit.js +34 -4
  154. package/test/offline/offline_manifest_parser_unit.js +1 -0
  155. package/test/offline/storage_compatibility_unit.js +1 -1
  156. package/test/offline/storage_integration.js +5 -4
  157. package/test/player_external.js +7 -7
  158. package/test/player_integration.js +22 -10
  159. package/test/player_src_equals_integration.js +81 -83
  160. package/test/player_unit.js +124 -1
  161. package/test/test/boot.js +9 -0
  162. package/test/test/externs/filters.js +4 -0
  163. package/test/test/util/fake_media_source_engine.js +11 -4
  164. package/test/test/util/manifest_generator.js +3 -1
  165. package/test/test/util/manifest_parser_util.js +4 -1
  166. package/test/test/util/offline_utils.js +1 -0
  167. package/test/test/util/simple_fakes.js +31 -2
  168. package/test/test/util/streaming_engine_util.js +1 -0
  169. package/test/test/util/test_scheme.js +24 -1
  170. package/test/test/util/util.js +4 -4
  171. package/test/text/cue_integration.js +2 -2
  172. package/test/text/lrc_text_parser_unit.js +6 -7
  173. package/test/text/mp4_ttml_parser_unit.js +6 -4
  174. package/test/text/mp4_vtt_parser_unit.js +6 -5
  175. package/test/text/sbv_text_parser_unit.js +5 -6
  176. package/test/text/srt_text_parser_unit.js +5 -6
  177. package/test/text/ssa_text_parser_unit.js +17 -29
  178. package/test/text/text_engine_unit.js +45 -5
  179. package/test/text/ttml_text_parser_unit.js +77 -77
  180. package/test/text/vtt_text_parser_unit.js +116 -59
  181. package/test/ui/ui_integration.js +0 -16
  182. package/test/ui/ui_unit.js +27 -0
  183. package/test/util/cmcd_manager_unit.js +3 -0
  184. package/test/util/mime_utils_unit.js +54 -0
  185. package/test/util/periods_unit.js +79 -0
  186. package/test/util/stream_utils_unit.js +23 -7
  187. package/ui/controls.js +65 -40
  188. package/ui/fullscreen_button.js +26 -6
  189. package/ui/less/containers.less +3 -3
  190. package/ui/locales/en.json +1 -0
  191. package/ui/locales/source.json +5 -0
  192. package/ui/resolution_selection.js +31 -33
  193. package/ui/ui.js +0 -17
  194. package/docs/tutorials/gsoc-ideas-list.md +0 -3
  195. package/docs/tutorials/upgrade-v2-5.md +0 -441
  196. package/docs/tutorials/upgrade-v3.md +0 -38
  197. package/lib/polyfill/mathround.js +0 -49
  198. package/lib/polyfill/patchedmediakeys_apple.js +0 -744
  199. package/lib/polyfill/patchedmediakeys_ms.js +0 -698
  200. package/lib/util/mutex.js +0 -52
  201. package/test/util/functional_unit.js +0 -82
@@ -1,698 +0,0 @@
1
- /*! @license
2
- * Shaka Player
3
- * Copyright 2016 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- goog.provide('shaka.polyfill.PatchedMediaKeysMs');
8
-
9
- goog.require('goog.asserts');
10
- goog.require('shaka.log');
11
- goog.require('shaka.media.DrmEngine');
12
- goog.require('shaka.polyfill');
13
- goog.require('shaka.util.BufferUtils');
14
- goog.require('shaka.util.EventManager');
15
- goog.require('shaka.util.FakeEvent');
16
- goog.require('shaka.util.FakeEventTarget');
17
- goog.require('shaka.util.MediaReadyState');
18
- goog.require('shaka.util.Pssh');
19
- goog.require('shaka.util.PublicPromise');
20
-
21
-
22
- /**
23
- * @summary A polyfill to implement
24
- * {@link https://bit.ly/EmeMar15 EME draft 12 March 2015}
25
- * on top of ms-prefixed
26
- * {@link https://www.w3.org/TR/2014/WD-encrypted-media-20140218/ EME v20140218}
27
- * @export
28
- */
29
- shaka.polyfill.PatchedMediaKeysMs = class {
30
- /**
31
- * Installs the polyfill if needed.
32
- * @export
33
- */
34
- static install() {
35
- if (!window.HTMLVideoElement || !window.MSMediaKeys ||
36
- (navigator.requestMediaKeySystemAccess &&
37
- // eslint-disable-next-line no-restricted-syntax
38
- MediaKeySystemAccess.prototype.getConfiguration)) {
39
- return;
40
- }
41
- shaka.log.info('Using ms-prefixed EME v20140218');
42
-
43
- // Alias
44
- const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs;
45
-
46
- // Delete mediaKeys to work around strict mode compatibility issues.
47
- // eslint-disable-next-line no-restricted-syntax
48
- delete HTMLMediaElement.prototype['mediaKeys'];
49
- // Work around read-only declaration for mediaKeys by using a string.
50
- // eslint-disable-next-line no-restricted-syntax
51
- HTMLMediaElement.prototype['mediaKeys'] = null;
52
-
53
- // Install patches
54
- window.MediaKeys = PatchedMediaKeysMs.MediaKeys;
55
- window.MediaKeySystemAccess = PatchedMediaKeysMs.MediaKeySystemAccess;
56
- navigator.requestMediaKeySystemAccess =
57
- PatchedMediaKeysMs.requestMediaKeySystemAccess;
58
- // eslint-disable-next-line no-restricted-syntax
59
- HTMLMediaElement.prototype.setMediaKeys =
60
- PatchedMediaKeysMs.MediaKeySystemAccess.setMediaKeys;
61
- }
62
-
63
- /**
64
- * An implementation of navigator.requestMediaKeySystemAccess.
65
- * Retrieves a MediaKeySystemAccess object.
66
- *
67
- * @this {!Navigator}
68
- * @param {string} keySystem
69
- * @param {!Array.<!MediaKeySystemConfiguration>} supportedConfigurations
70
- * @return {!Promise.<!MediaKeySystemAccess>}
71
- */
72
- static requestMediaKeySystemAccess(keySystem, supportedConfigurations) {
73
- shaka.log.debug('PatchedMediaKeysMs.requestMediaKeySystemAccess');
74
- goog.asserts.assert(this == navigator,
75
- 'bad "this" for requestMediaKeySystemAccess');
76
-
77
- // Alias.
78
- const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs;
79
- try {
80
- const access = new PatchedMediaKeysMs.MediaKeySystemAccess(
81
- keySystem, supportedConfigurations);
82
- return Promise.resolve(/** @type {!MediaKeySystemAccess} */ (access));
83
- } catch (exception) {
84
- return Promise.reject(exception);
85
- }
86
- }
87
-
88
- /**
89
- * Handler for the native media elements msNeedKey event.
90
- *
91
- * @this {!HTMLMediaElement}
92
- * @param {!MediaKeyEvent} event
93
- * @suppress {constantProperty} We reassign what would be const on a real
94
- * MediaEncryptedEvent, but in our look-alike event.
95
- * @private
96
- */
97
- static onMsNeedKey_(event) {
98
- shaka.log.debug('PatchedMediaKeysMs.onMsNeedKey_', event);
99
- if (!event.initData) {
100
- return;
101
- }
102
-
103
- const event2 = new CustomEvent('encrypted');
104
- const encryptedEvent =
105
- /** @type {!MediaEncryptedEvent} */(/** @type {?} */(event2));
106
- encryptedEvent.initDataType = 'cenc';
107
- encryptedEvent.initData = shaka.util.BufferUtils.toArrayBuffer(
108
- shaka.util.Pssh.normaliseInitData(event.initData));
109
-
110
- this.dispatchEvent(event2);
111
- }
112
- };
113
-
114
-
115
- /**
116
- * An implementation of MediaKeySystemAccess.
117
- *
118
- * @implements {MediaKeySystemAccess}
119
- */
120
- shaka.polyfill.PatchedMediaKeysMs.MediaKeySystemAccess = class {
121
- /**
122
- * @param {string} keySystem
123
- * @param {!Array.<!MediaKeySystemConfiguration>} supportedConfigurations
124
- */
125
- constructor(keySystem, supportedConfigurations) {
126
- shaka.log.debug('PatchedMediaKeysMs.MediaKeySystemAccess');
127
-
128
- /** @type {string} */
129
- this.keySystem = keySystem;
130
-
131
- /** @private {!MediaKeySystemConfiguration} */
132
- this.configuration_;
133
-
134
- const allowPersistentState = false;
135
-
136
- let success = false;
137
- for (const cfg of supportedConfigurations) {
138
- // Create a new config object and start adding in the pieces which we
139
- // find support for. We will return this from getConfiguration() if
140
- // asked.
141
- /** @type {!MediaKeySystemConfiguration} */
142
- const newCfg = {
143
- 'audioCapabilities': [],
144
- 'videoCapabilities': [],
145
- // It is technically against spec to return these as optional, but we
146
- // don't truly know their values from the prefixed API:
147
- 'persistentState': 'optional',
148
- 'distinctiveIdentifier': 'optional',
149
- // Pretend the requested init data types are supported, since we don't
150
- // really know that either:
151
- 'initDataTypes': cfg.initDataTypes,
152
- 'sessionTypes': ['temporary'],
153
- 'label': cfg.label,
154
- };
155
-
156
- // PatchedMediaKeysMs tests for key system availability through
157
- // MSMediaKeys.isTypeSupported
158
- let ranAnyTests = false;
159
- if (cfg.audioCapabilities) {
160
- for (const cap of cfg.audioCapabilities) {
161
- if (cap.contentType) {
162
- ranAnyTests = true;
163
- const contentType = cap.contentType.split(';')[0];
164
- if (MSMediaKeys.isTypeSupported(this.keySystem, contentType)) {
165
- newCfg.audioCapabilities.push(cap);
166
- success = true;
167
- }
168
- }
169
- }
170
- }
171
- if (cfg.videoCapabilities) {
172
- for (const cap of cfg.videoCapabilities) {
173
- if (cap.contentType) {
174
- ranAnyTests = true;
175
- const contentType = cap.contentType.split(';')[0];
176
- if (MSMediaKeys.isTypeSupported(this.keySystem, contentType)) {
177
- newCfg.videoCapabilities.push(cap);
178
- success = true;
179
- }
180
- }
181
- }
182
- }
183
-
184
- if (!ranAnyTests) {
185
- // If no specific types were requested, we check all common types to
186
- // find out if the key system is present at all.
187
- success = MSMediaKeys.isTypeSupported(this.keySystem, 'video/mp4');
188
- }
189
- if (cfg.persistentState == 'required') {
190
- if (allowPersistentState) {
191
- newCfg.persistentState = 'required';
192
- newCfg.sessionTypes = ['persistent-license'];
193
- } else {
194
- success = false;
195
- }
196
- }
197
-
198
- if (success) {
199
- this.configuration_ = newCfg;
200
- return;
201
- }
202
- } // for each cfg in supportedConfigurations
203
-
204
- // According to the spec, this should be a DOMException, but there is not a
205
- // public constructor for that. So we make this look-alike instead.
206
- const unsupportedKeySystemError = new Error('Unsupported keySystem');
207
- unsupportedKeySystemError.name = 'NotSupportedError';
208
- unsupportedKeySystemError['code'] = DOMException.NOT_SUPPORTED_ERR;
209
- throw unsupportedKeySystemError;
210
- }
211
-
212
- /** @override */
213
- createMediaKeys() {
214
- shaka.log.debug(
215
- 'PatchedMediaKeysMs.MediaKeySystemAccess.createMediaKeys');
216
-
217
- // Alias
218
- const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs;
219
-
220
- const mediaKeys = new PatchedMediaKeysMs.MediaKeys(this.keySystem);
221
- return Promise.resolve(/** @type {!MediaKeys} */ (mediaKeys));
222
- }
223
-
224
- /** @override */
225
- getConfiguration() {
226
- shaka.log.debug(
227
- 'PatchedMediaKeysMs.MediaKeySystemAccess.getConfiguration');
228
- return this.configuration_;
229
- }
230
-
231
- /**
232
- * An implementation of HTMLMediaElement.prototype.setMediaKeys.
233
- * Attaches a MediaKeys object to the media element.
234
- *
235
- * @this {!HTMLMediaElement}
236
- * @param {MediaKeys} mediaKeys
237
- * @return {!Promise}
238
- */
239
- static setMediaKeys(mediaKeys) {
240
- shaka.log.debug('PatchedMediaKeysMs.setMediaKeys');
241
- goog.asserts.assert(this instanceof HTMLMediaElement,
242
- 'bad "this" for setMediaKeys');
243
-
244
- // Alias
245
- const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs;
246
-
247
- const newMediaKeys =
248
- /** @type {shaka.polyfill.PatchedMediaKeysMs.MediaKeys} */ (
249
- mediaKeys);
250
- const oldMediaKeys =
251
- /** @type {shaka.polyfill.PatchedMediaKeysMs.MediaKeys} */ (
252
- this.mediaKeys);
253
-
254
- if (oldMediaKeys && oldMediaKeys != newMediaKeys) {
255
- goog.asserts.assert(oldMediaKeys instanceof PatchedMediaKeysMs.MediaKeys,
256
- 'non-polyfill instance of oldMediaKeys');
257
- // Have the old MediaKeys stop listening to events on the video tag.
258
- oldMediaKeys.setMedia(null);
259
- }
260
-
261
- delete this['mediaKeys']; // in case there is an existing getter
262
- this['mediaKeys'] = mediaKeys; // work around read-only declaration
263
-
264
- if (newMediaKeys) {
265
- goog.asserts.assert(newMediaKeys instanceof PatchedMediaKeysMs.MediaKeys,
266
- 'non-polyfill instance of newMediaKeys');
267
- return newMediaKeys.setMedia(this);
268
- }
269
-
270
- return Promise.resolve();
271
- }
272
- };
273
-
274
-
275
- /**
276
- * An implementation of MediaKeys.
277
- *
278
- * @implements {MediaKeys}
279
- */
280
- shaka.polyfill.PatchedMediaKeysMs.MediaKeys = class {
281
- /** @param {string} keySystem */
282
- constructor(keySystem) {
283
- shaka.log.debug('PatchedMediaKeysMs.MediaKeys');
284
-
285
- /** @private {!MSMediaKeys} */
286
- this.nativeMediaKeys_ = new MSMediaKeys(keySystem);
287
-
288
- /** @private {!shaka.util.EventManager} */
289
- this.eventManager_ = new shaka.util.EventManager();
290
- }
291
-
292
- /** @override */
293
- createSession(sessionType) {
294
- shaka.log.debug('PatchedMediaKeysMs.MediaKeys.createSession');
295
-
296
- sessionType = sessionType || 'temporary';
297
- // For now, only the 'temporary' type is supported.
298
- if (sessionType != 'temporary') {
299
- throw new TypeError('Session type ' + sessionType +
300
- ' is unsupported on this platform.');
301
- }
302
-
303
- // Alias
304
- const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs;
305
-
306
- return new PatchedMediaKeysMs.MediaKeySession(
307
- this.nativeMediaKeys_, sessionType);
308
- }
309
-
310
- /** @override */
311
- setServerCertificate(serverCertificate) {
312
- shaka.log.debug('PatchedMediaKeysMs.MediaKeys.setServerCertificate');
313
-
314
- // There is no equivalent in PatchedMediaKeysMs, so return failure.
315
- return Promise.resolve(false);
316
- }
317
-
318
- /**
319
- * @param {HTMLMediaElement} media
320
- * @protected
321
- * @return {!Promise}
322
- */
323
- setMedia(media) {
324
- // Alias
325
- const PatchedMediaKeysMs = shaka.polyfill.PatchedMediaKeysMs;
326
-
327
- // Remove any old listeners.
328
- this.eventManager_.removeAll();
329
-
330
- // It is valid for media to be null; null is used to flag that event
331
- // handlers need to be cleaned up.
332
- if (!media) {
333
- return Promise.resolve();
334
- }
335
-
336
- // Intercept and translate these prefixed EME events.
337
- this.eventManager_.listen(media, 'msneedkey',
338
- /** @type {shaka.util.EventManager.ListenerType} */
339
- (PatchedMediaKeysMs.onMsNeedKey_));
340
-
341
- // Wrap native HTMLMediaElement.msSetMediaKeys with a Promise.
342
- try {
343
- // Edge requires that readyState >=1 before mediaKeys can be set,
344
- // so check this and wait for loadedmetadata if we are not in the
345
- // correct state
346
- shaka.util.MediaReadyState.waitForReadyState(media,
347
- HTMLMediaElement.HAVE_METADATA,
348
- this.eventManager_, () => {
349
- media.msSetMediaKeys(this.nativeMediaKeys_);
350
- });
351
-
352
- return Promise.resolve();
353
- } catch (exception) {
354
- return Promise.reject(exception);
355
- }
356
- }
357
- };
358
-
359
-
360
- /**
361
- * An implementation of MediaKeySession.
362
- *
363
- * @implements {MediaKeySession}
364
- */
365
- shaka.polyfill.PatchedMediaKeysMs.MediaKeySession =
366
- class extends shaka.util.FakeEventTarget {
367
- /**
368
- * @param {MSMediaKeys} nativeMediaKeys
369
- * @param {string} sessionType
370
- */
371
- constructor(nativeMediaKeys, sessionType) {
372
- shaka.log.debug('PatchedMediaKeysMs.MediaKeySession');
373
- super();
374
-
375
- /**
376
- * The native MediaKeySession, which will be created in generateRequest.
377
- * @private {MSMediaKeySession}
378
- */
379
- this.nativeMediaKeySession_ = null;
380
-
381
- /** @private {MSMediaKeys} */
382
- this.nativeMediaKeys_ = nativeMediaKeys;
383
-
384
- // Promises that are resolved later
385
- /** @private {shaka.util.PublicPromise} */
386
- this.generateRequestPromise_ = null;
387
-
388
- /** @private {shaka.util.PublicPromise} */
389
- this.updatePromise_ = null;
390
-
391
- /** @private {!shaka.util.EventManager} */
392
- this.eventManager_ = new shaka.util.EventManager();
393
-
394
- /** @type {string} */
395
- this.sessionId = '';
396
-
397
- /** @type {number} */
398
- this.expiration = NaN;
399
-
400
- /** @type {!shaka.util.PublicPromise} */
401
- this.closed = new shaka.util.PublicPromise();
402
-
403
- /** @type {!shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap} */
404
- this.keyStatuses =
405
- new shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap();
406
- }
407
-
408
- /** @override */
409
- generateRequest(initDataType, initData) {
410
- shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.generateRequest');
411
-
412
- this.generateRequestPromise_ = new shaka.util.PublicPromise();
413
-
414
- try {
415
- // This EME spec version requires a MIME content type as the 1st param to
416
- // createSession, but doesn't seem to matter what the value is.
417
-
418
- // NOTE: Edge 12 only accepts Uint8Array.
419
- this.nativeMediaKeySession_ = this.nativeMediaKeys_.createSession(
420
- 'video/mp4', shaka.util.BufferUtils.toUint8(initData), null);
421
-
422
- // Attach session event handlers here.
423
- this.eventManager_.listen(this.nativeMediaKeySession_, 'mskeymessage',
424
- /** @type {shaka.util.EventManager.ListenerType} */
425
- ((event) => this.onMsKeyMessage_(event)));
426
- this.eventManager_.listen(this.nativeMediaKeySession_, 'mskeyadded',
427
- /** @type {shaka.util.EventManager.ListenerType} */
428
- ((event) => this.onMsKeyAdded_(event)));
429
- this.eventManager_.listen(this.nativeMediaKeySession_, 'mskeyerror',
430
- /** @type {shaka.util.EventManager.ListenerType} */
431
- ((event) => this.onMsKeyError_(event)));
432
-
433
- this.updateKeyStatus_('status-pending');
434
- } catch (exception) {
435
- this.generateRequestPromise_.reject(exception);
436
- }
437
-
438
- return this.generateRequestPromise_;
439
- }
440
-
441
- /** @override */
442
- load() {
443
- shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.load');
444
-
445
- return Promise.reject(new Error('MediaKeySession.load not yet supported'));
446
- }
447
-
448
- /** @override */
449
- update(response) {
450
- shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.update');
451
-
452
- this.updatePromise_ = new shaka.util.PublicPromise();
453
-
454
- try {
455
- // Pass through to the native session.
456
- // NOTE: Edge 12 only accepts Uint8Array.
457
- this.nativeMediaKeySession_.update(
458
- shaka.util.BufferUtils.toUint8(response));
459
- } catch (exception) {
460
- this.updatePromise_.reject(exception);
461
- }
462
-
463
- return this.updatePromise_;
464
- }
465
-
466
- /** @override */
467
- close() {
468
- shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.close');
469
-
470
- try {
471
- // Pass through to the native session.
472
- // NOTE: IE seems to have a spec discrepancy here - v2010218 should have
473
- // MediaKeySession.release, but actually uses "close". The next version of
474
- // the spec is the initial Promise based one, so it's not the target spec
475
- // either.
476
- this.nativeMediaKeySession_.close();
477
-
478
- this.closed.resolve();
479
- this.eventManager_.removeAll();
480
- } catch (exception) {
481
- this.closed.reject(exception);
482
- }
483
-
484
- return this.closed;
485
- }
486
-
487
- /** @override */
488
- remove() {
489
- shaka.log.debug('PatchedMediaKeysMs.MediaKeySession.remove');
490
-
491
- return Promise.reject(new Error(
492
- 'MediaKeySession.remove is only applicable for persistent licenses, ' +
493
- 'which are not supported on this platform'));
494
- }
495
-
496
- /**
497
- * Handler for the native keymessage event on MSMediaKeySession.
498
- *
499
- * @param {!MediaKeyEvent} event
500
- * @private
501
- */
502
- onMsKeyMessage_(event) {
503
- shaka.log.debug('PatchedMediaKeysMs.onMsKeyMessage_', event);
504
-
505
- // We can now resolve this.generateRequestPromise, which should be non-null.
506
- goog.asserts.assert(this.generateRequestPromise_,
507
- 'generateRequestPromise_ not set in onMsKeyMessage_');
508
- if (this.generateRequestPromise_) {
509
- this.generateRequestPromise_.resolve();
510
- this.generateRequestPromise_ = null;
511
- }
512
-
513
- const isNew = this.keyStatuses.getStatus() == undefined;
514
-
515
- const data = new Map()
516
- .set('messageType', isNew ? 'license-request' : 'license-renewal')
517
- .set('message', shaka.util.BufferUtils.toArrayBuffer(event.message));
518
- const event2 = new shaka.util.FakeEvent('message', data);
519
-
520
- this.dispatchEvent(event2);
521
- }
522
-
523
- /**
524
- * Handler for the native keyadded event on MSMediaKeySession.
525
- *
526
- * @param {!MediaKeyEvent} event
527
- * @private
528
- */
529
- onMsKeyAdded_(event) {
530
- shaka.log.debug('PatchedMediaKeysMs.onMsKeyAdded_', event);
531
-
532
- // PlayReady's concept of persistent licenses makes emulation difficult
533
- // here. A license policy can say that the license persists, which causes
534
- // the CDM to store it for use in a later session. The result is that in
535
- // IE11, the CDM fires 'mskeyadded' without ever firing 'mskeymessage'.
536
- if (this.generateRequestPromise_) {
537
- shaka.log.debug('Simulating completion for a PR persistent license.');
538
- goog.asserts.assert(!this.updatePromise_,
539
- 'updatePromise_ and generateRequestPromise_ set in onMsKeyAdded_');
540
- this.updateKeyStatus_('usable');
541
- this.generateRequestPromise_.resolve();
542
- this.generateRequestPromise_ = null;
543
- return;
544
- }
545
-
546
- // We can now resolve this.updatePromise, which should be non-null.
547
- goog.asserts.assert(this.updatePromise_,
548
- 'updatePromise_ not set in onMsKeyAdded_');
549
- if (this.updatePromise_) {
550
- this.updateKeyStatus_('usable');
551
- this.updatePromise_.resolve();
552
- this.updatePromise_ = null;
553
- }
554
- }
555
-
556
- /**
557
- * Handler for the native keyerror event on MSMediaKeySession.
558
- *
559
- * @param {!MediaKeyEvent} event
560
- * @private
561
- */
562
- onMsKeyError_(event) {
563
- shaka.log.debug('PatchedMediaKeysMs.onMsKeyError_', event);
564
-
565
- const error = new Error('EME PatchedMediaKeysMs key error');
566
- error['errorCode'] = this.nativeMediaKeySession_.error;
567
-
568
- if (this.generateRequestPromise_ != null) {
569
- this.generateRequestPromise_.reject(error);
570
- this.generateRequestPromise_ = null;
571
- } else if (this.updatePromise_ != null) {
572
- this.updatePromise_.reject(error);
573
- this.updatePromise_ = null;
574
- } else {
575
- // Unexpected error - map native codes to standardised key statuses.
576
- // Possible values of this.nativeMediaKeySession_.error.code:
577
- // MS_MEDIA_KEYERR_UNKNOWN = 1
578
- // MS_MEDIA_KEYERR_CLIENT = 2
579
- // MS_MEDIA_KEYERR_SERVICE = 3
580
- // MS_MEDIA_KEYERR_OUTPUT = 4
581
- // MS_MEDIA_KEYERR_HARDWARECHANGE = 5
582
- // MS_MEDIA_KEYERR_DOMAIN = 6
583
-
584
- switch (this.nativeMediaKeySession_.error.code) {
585
- case MSMediaKeyError.MS_MEDIA_KEYERR_OUTPUT:
586
- case MSMediaKeyError.MS_MEDIA_KEYERR_HARDWARECHANGE:
587
- this.updateKeyStatus_('output-not-allowed');
588
- break;
589
- default:
590
- this.updateKeyStatus_('internal-error');
591
- break;
592
- }
593
- }
594
- }
595
-
596
- /**
597
- * Updates key status and dispatch a 'keystatuseschange' event.
598
- *
599
- * @param {string} status
600
- * @private
601
- */
602
- updateKeyStatus_(status) {
603
- this.keyStatuses.setStatus(status);
604
- const event = new shaka.util.FakeEvent('keystatuseschange');
605
- this.dispatchEvent(event);
606
- }
607
- };
608
-
609
-
610
- /**
611
- * @summary An implementation of MediaKeyStatusMap.
612
- * This fakes a map with a single key ID.
613
- *
614
- * @todo Consolidate the MediaKeyStatusMap types in these polyfills.
615
- * @implements {MediaKeyStatusMap}
616
- */
617
- shaka.polyfill.PatchedMediaKeysMs.MediaKeyStatusMap = class {
618
- /** */
619
- constructor() {
620
- /**
621
- * @type {number}
622
- */
623
- this.size = 0;
624
-
625
- /**
626
- * @private {string|undefined}
627
- */
628
- this.status_ = undefined;
629
- }
630
-
631
- /**
632
- * An internal method used by the session to set key status.
633
- * @param {string|undefined} status
634
- */
635
- setStatus(status) {
636
- this.size = status == undefined ? 0 : 1;
637
- this.status_ = status;
638
- }
639
-
640
- /**
641
- * An internal method used by the session to get key status.
642
- * @return {string|undefined}
643
- */
644
- getStatus() {
645
- return this.status_;
646
- }
647
-
648
- /** @override */
649
- forEach(fn) {
650
- if (this.status_) {
651
- fn(this.status_, shaka.media.DrmEngine.DUMMY_KEY_ID.value());
652
- }
653
- }
654
-
655
- /** @override */
656
- get(keyId) {
657
- if (this.has(keyId)) {
658
- return this.status_;
659
- }
660
- return undefined;
661
- }
662
-
663
- /** @override */
664
- has(keyId) {
665
- const fakeKeyId = shaka.media.DrmEngine.DUMMY_KEY_ID.value();
666
- if (this.status_ && shaka.util.BufferUtils.equal(keyId, fakeKeyId)) {
667
- return true;
668
- }
669
- return false;
670
- }
671
-
672
- /**
673
- * @suppress {missingReturn}
674
- * @override
675
- */
676
- entries() {
677
- goog.asserts.assert(false, 'Not used! Provided only for the compiler.');
678
- }
679
-
680
- /**
681
- * @suppress {missingReturn}
682
- * @override
683
- */
684
- keys() {
685
- goog.asserts.assert(false, 'Not used! Provided only for the compiler.');
686
- }
687
-
688
- /**
689
- * @suppress {missingReturn}
690
- * @override
691
- */
692
- values() {
693
- goog.asserts.assert(false, 'Not used! Provided only for the compiler.');
694
- }
695
- };
696
-
697
-
698
- shaka.polyfill.register(shaka.polyfill.PatchedMediaKeysMs.install);