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
@@ -238,6 +238,25 @@ describe('ManifestTextParser', () => {
238
238
  '#EXTM3U\n' +
239
239
  '#EXT-X-MEDIA:CODECS="avc1.64002a,mp4a.40.2",AUDIO="a1,a2"',
240
240
 
241
+ // manifest URI:
242
+ 'https://test/manifest.m3u8');
243
+
244
+ verifyPlaylist(
245
+ {
246
+ type: shaka.hls.PlaylistType.MASTER,
247
+ tags: [
248
+ new shaka.hls.Tag(/* id= */ 3, 'EXT-X-MEDIA',
249
+ [
250
+ new shaka.hls.Attribute('CODECS',
251
+ 'av01.0.08M.08,mp4a.40.2'),
252
+ ]),
253
+ ],
254
+ },
255
+
256
+ // playlist text:
257
+ '#EXTM3U\n' +
258
+ '#EXT-X-MEDIA:CODECS="av01.0.08M.08,mp4a.40.2"',
259
+
241
260
  // manifest URI:
242
261
  'https://test/manifest.m3u8');
243
262
  });
@@ -756,11 +756,6 @@ describe('DrmEngine', () => {
756
756
  expect(mockVideo.setMediaKeys).not.toHaveBeenCalled();
757
757
  });
758
758
 
759
- it('sets MediaKeys for encrypted content', async () => {
760
- await initAndAttach();
761
- expect(mockVideo.setMediaKeys).toHaveBeenCalledWith(mockMediaKeys);
762
- });
763
-
764
759
  it('sets server certificate if present in config', async () => {
765
760
  const cert = new Uint8Array(1);
766
761
  config.advanced['drm.abc'] = createAdvancedConfig(cert);
@@ -857,7 +852,7 @@ describe('DrmEngine', () => {
857
852
  /** @type {!Uint8Array} */
858
853
  const initData1 = new Uint8Array(5);
859
854
  /** @type {!Uint8Array} */
860
- const initData2 = new Uint8Array(0);
855
+ const initData2 = new Uint8Array(1);
861
856
  /** @type {!Uint8Array} */
862
857
  const initData3 = new Uint8Array(10);
863
858
 
@@ -999,12 +994,23 @@ describe('DrmEngine', () => {
999
994
  mockVideo.setMediaKeys.and.returnValue(Promise.reject(
1000
995
  new Error('whoops!')));
1001
996
 
1002
- const expected = Util.jasmineError(new shaka.util.Error(
997
+ tweakDrmInfos((drmInfos) => {
998
+ drmInfos[0].initData = [
999
+ {initData: new Uint8Array(1), initDataType: 'cenc', keyId: null},
1000
+ ];
1001
+ });
1002
+
1003
+ onErrorSpy.and.stub();
1004
+
1005
+ await initAndAttach();
1006
+
1007
+ expect(onErrorSpy).toHaveBeenCalled();
1008
+ const error = onErrorSpy.calls.argsFor(0)[0];
1009
+ shaka.test.Util.expectToEqualError(error, new shaka.util.Error(
1003
1010
  shaka.util.Error.Severity.CRITICAL,
1004
1011
  shaka.util.Error.Category.DRM,
1005
1012
  shaka.util.Error.Code.FAILED_TO_ATTACH_TO_VIDEO,
1006
1013
  'whoops!'));
1007
- await expectAsync(initAndAttach()).toBeRejectedWith(expected);
1008
1014
  });
1009
1015
 
1010
1016
  it('fails with an error if setServerCertificate fails', async () => {
@@ -1067,10 +1073,8 @@ describe('DrmEngine', () => {
1067
1073
  const initData1 = new Uint8Array(1);
1068
1074
  const initData2 = new Uint8Array(2);
1069
1075
 
1070
- mockVideo.on['encrypted'](
1071
- {initDataType: 'webm', initData: initData1, keyId: null});
1072
- mockVideo.on['encrypted'](
1073
- {initDataType: 'cenc', initData: initData2, keyId: null});
1076
+ await sendEncryptedEvent('webm', initData1);
1077
+ await sendEncryptedEvent('cenc', initData2);
1074
1078
 
1075
1079
  expect(mockMediaKeys.createSession).toHaveBeenCalledTimes(2);
1076
1080
  expect(session1.generateRequest)
@@ -1081,32 +1085,23 @@ describe('DrmEngine', () => {
1081
1085
 
1082
1086
  it('suppresses duplicate initDatas', async () => {
1083
1087
  await initAndAttach();
1088
+
1084
1089
  const initData1 = new Uint8Array(1);
1085
- const initData2 = new Uint8Array(1); // identical to initData1
1086
1090
 
1087
- mockVideo.on['encrypted'](
1088
- {initDataType: 'webm', initData: initData1, keyId: null});
1089
- mockVideo.on['encrypted'](
1090
- {initDataType: 'cenc', initData: initData2, keyId: null});
1091
+ await sendEncryptedEvent('webm', initData1);
1092
+ await sendEncryptedEvent('cenc'); // identical to webm initData
1091
1093
 
1092
1094
  expect(mockMediaKeys.createSession).toHaveBeenCalledTimes(1);
1093
1095
  expect(session1.generateRequest)
1094
1096
  .toHaveBeenCalledWith('webm', initData1);
1095
1097
  });
1096
1098
 
1097
- it('is ignored when init data is in DrmInfo', async () => {
1098
- // Set up an init data override in the manifest:
1099
- tweakDrmInfos((drmInfos) => {
1100
- drmInfos[0].initData = [
1101
- {initData: new Uint8Array(0), initDataType: 'cenc', keyId: null},
1102
- ];
1103
- });
1104
-
1099
+ it('set media keys when not already done at startup', async () => {
1105
1100
  await initAndAttach();
1106
- // We already created a session for the init data override.
1101
+ await sendEncryptedEvent();
1102
+
1103
+ expect(mockVideo.setMediaKeys).toHaveBeenCalledTimes(1);
1107
1104
  expect(mockMediaKeys.createSession).toHaveBeenCalledTimes(1);
1108
- // We aren't even listening for 'encrypted' events.
1109
- expect(mockVideo.on['encrypted']).toBe(undefined);
1110
1105
  });
1111
1106
 
1112
1107
  it('dispatches an error if createSession fails', async () => {
@@ -1114,9 +1109,7 @@ describe('DrmEngine', () => {
1114
1109
  onErrorSpy.and.stub();
1115
1110
 
1116
1111
  await initAndAttach();
1117
- const initData1 = new Uint8Array(1);
1118
- mockVideo.on['encrypted'](
1119
- {initDataType: 'webm', initData: initData1, keyId: null});
1112
+ await sendEncryptedEvent();
1120
1113
 
1121
1114
  expect(onErrorSpy).toHaveBeenCalled();
1122
1115
  const error = onErrorSpy.calls.argsFor(0)[0];
@@ -1136,9 +1129,7 @@ describe('DrmEngine', () => {
1136
1129
  onErrorSpy.and.stub();
1137
1130
 
1138
1131
  await initAndAttach();
1139
- const initData1 = new Uint8Array(1);
1140
- mockVideo.on['encrypted'](
1141
- {initDataType: 'webm', initData: initData1, keyId: null});
1132
+ await sendEncryptedEvent();
1142
1133
 
1143
1134
  expect(onErrorSpy).toHaveBeenCalled();
1144
1135
  const error = onErrorSpy.calls.argsFor(0)[0];
@@ -1152,9 +1143,7 @@ describe('DrmEngine', () => {
1152
1143
  describe('message', () => {
1153
1144
  it('is listened for', async () => {
1154
1145
  await initAndAttach();
1155
- const initData = new Uint8Array(0);
1156
- mockVideo.on['encrypted'](
1157
- {initDataType: 'webm', initData: initData, keyId: null});
1146
+ await sendEncryptedEvent();
1158
1147
 
1159
1148
  expect(session1.addEventListener).toHaveBeenCalledWith(
1160
1149
  'message', jasmine.any(Function), jasmine.anything());
@@ -1194,9 +1183,7 @@ describe('DrmEngine', () => {
1194
1183
  onErrorSpy.and.stub();
1195
1184
 
1196
1185
  await initAndAttach();
1197
- const initData = new Uint8Array(0);
1198
- mockVideo.on['encrypted'](
1199
- {initDataType: 'webm', initData: initData, keyId: null});
1186
+ await sendEncryptedEvent();
1200
1187
 
1201
1188
  // Simulate a permission error from the web server.
1202
1189
  const netError = new shaka.util.Error(
@@ -1232,9 +1219,7 @@ describe('DrmEngine', () => {
1232
1219
  async function sendMessageTest(
1233
1220
  expectedUrl, messageType = 'license-request') {
1234
1221
  await initAndAttach();
1235
- const initData = new Uint8Array(0);
1236
- mockVideo.on['encrypted'](
1237
- {initDataType: 'webm', initData: initData, keyId: null});
1222
+ await sendEncryptedEvent();
1238
1223
 
1239
1224
  const operation = shaka.util.AbortableOperation.completed({});
1240
1225
  fakeNetEngine.request.and.returnValue(operation);
@@ -1256,9 +1241,7 @@ describe('DrmEngine', () => {
1256
1241
  describe('keystatuseschange', () => {
1257
1242
  it('is listened for', async () => {
1258
1243
  await initAndAttach();
1259
- const initData = new Uint8Array(0);
1260
- mockVideo.on['encrypted'](
1261
- {initDataType: 'webm', initData: initData, keyId: null});
1244
+ await sendEncryptedEvent();
1262
1245
 
1263
1246
  expect(session1.addEventListener).toHaveBeenCalledWith(
1264
1247
  'keystatuseschange', jasmine.any(Function), jasmine.anything());
@@ -1266,9 +1249,7 @@ describe('DrmEngine', () => {
1266
1249
 
1267
1250
  it('triggers callback', async () => {
1268
1251
  await initAndAttach();
1269
- const initData = new Uint8Array(0);
1270
- mockVideo.on['encrypted'](
1271
- {initDataType: 'webm', initData: initData, keyId: null});
1252
+ await sendEncryptedEvent();
1272
1253
 
1273
1254
  const keyId1 = makeKeyId(1);
1274
1255
  const keyId2 = makeKeyId(2);
@@ -1294,10 +1275,7 @@ describe('DrmEngine', () => {
1294
1275
  // See https://github.com/shaka-project/shaka-player/issues/1541
1295
1276
  it('does not update public key statuses before callback', async () => {
1296
1277
  await initAndAttach();
1297
-
1298
- const initData = new Uint8Array(0);
1299
- mockVideo.on['encrypted'](
1300
- {initDataType: 'webm', initData: initData, keyId: null});
1278
+ await sendEncryptedEvent();
1301
1279
 
1302
1280
  const keyId1 = makeKeyId(1);
1303
1281
  const keyId2 = makeKeyId(2);
@@ -1374,9 +1352,7 @@ describe('DrmEngine', () => {
1374
1352
  await initAndAttach();
1375
1353
  expect(onErrorSpy).not.toHaveBeenCalled();
1376
1354
 
1377
- const initData = new Uint8Array(0);
1378
- mockVideo.on['encrypted'](
1379
- {initDataType: 'webm', initData: initData, keyId: null});
1355
+ await sendEncryptedEvent();
1380
1356
 
1381
1357
  const keyId1 = makeKeyId(1);
1382
1358
  const keyId2 = makeKeyId(2);
@@ -1423,9 +1399,7 @@ describe('DrmEngine', () => {
1423
1399
  await initAndAttach();
1424
1400
  expect(onErrorSpy).not.toHaveBeenCalled();
1425
1401
 
1426
- const initData = new Uint8Array(0);
1427
- mockVideo.on['encrypted'](
1428
- {initDataType: 'webm', initData: initData, keyId: null});
1402
+ await sendEncryptedEvent();
1429
1403
 
1430
1404
  const keyId1 = makeKeyId(1);
1431
1405
  const keyId2 = makeKeyId(2);
@@ -1469,9 +1443,7 @@ describe('DrmEngine', () => {
1469
1443
  const license = new Uint8Array(0);
1470
1444
 
1471
1445
  await initAndAttach();
1472
- const initData = new Uint8Array(0);
1473
- mockVideo.on['encrypted'](
1474
- {initDataType: 'webm', initData: initData, keyId: null});
1446
+ await sendEncryptedEvent();
1475
1447
 
1476
1448
  fakeNetEngine.setResponseValue('http://abc.drm/license', license);
1477
1449
  const message = new Uint8Array(0);
@@ -1530,9 +1502,8 @@ describe('DrmEngine', () => {
1530
1502
 
1531
1503
  it('publishes an event if update succeeds', async () => {
1532
1504
  await initAndAttach();
1533
- const initData = new Uint8Array(1);
1534
- mockVideo.on['encrypted'](
1535
- {initDataType: 'webm', initData: initData, keyId: null});
1505
+ await sendEncryptedEvent();
1506
+
1536
1507
  const message = new Uint8Array(0);
1537
1508
  session1.on['message']({target: session1, message: message});
1538
1509
  session1.update.and.returnValue(Promise.resolve());
@@ -1548,9 +1519,7 @@ describe('DrmEngine', () => {
1548
1519
  const license = new Uint8Array(0);
1549
1520
 
1550
1521
  await initAndAttach();
1551
- const initData = new Uint8Array(0);
1552
- mockVideo.on['encrypted'](
1553
- {initDataType: 'webm', initData: initData, keyId: null});
1522
+ await sendEncryptedEvent();
1554
1523
 
1555
1524
  fakeNetEngine.setResponseValue('http://abc.drm/license', license);
1556
1525
  const message = new Uint8Array(0);
@@ -1571,12 +1540,9 @@ describe('DrmEngine', () => {
1571
1540
  describe('destroy', () => {
1572
1541
  it('tears down MediaKeys and active sessions', async () => {
1573
1542
  await initAndAttach();
1574
- const initData1 = new Uint8Array(1);
1575
- const initData2 = new Uint8Array(2);
1576
- mockVideo.on['encrypted'](
1577
- {initDataType: 'webm', initData: initData1, keyId: null});
1578
- mockVideo.on['encrypted'](
1579
- {initDataType: 'webm', initData: initData2, keyId: null});
1543
+
1544
+ await sendEncryptedEvent('webm');
1545
+ await sendEncryptedEvent('cenc', new Uint8Array(2));
1580
1546
 
1581
1547
  const message = new Uint8Array(0);
1582
1548
  session1.on['message']({target: session1, message: message});
@@ -1601,12 +1567,8 @@ describe('DrmEngine', () => {
1601
1567
  drmEngine.configure(config);
1602
1568
 
1603
1569
  await initAndAttach();
1604
- const initData1 = new Uint8Array(1);
1605
- const initData2 = new Uint8Array(2);
1606
- mockVideo.on['encrypted'](
1607
- {initDataType: 'webm', initData: initData1, keyId: null});
1608
- mockVideo.on['encrypted'](
1609
- {initDataType: 'webm', initData: initData2, keyId: null});
1570
+ await sendEncryptedEvent('webm');
1571
+ await sendEncryptedEvent('cenc', new Uint8Array(2));
1610
1572
 
1611
1573
  const message = new Uint8Array(0);
1612
1574
  session1.on['message']({target: session1, message: message});
@@ -1627,12 +1589,8 @@ describe('DrmEngine', () => {
1627
1589
 
1628
1590
  it('swallows errors when closing sessions', async () => {
1629
1591
  await initAndAttach();
1630
- const initData1 = new Uint8Array(1);
1631
- const initData2 = new Uint8Array(2);
1632
- mockVideo.on['encrypted'](
1633
- {initDataType: 'webm', initData: initData1, keyId: null});
1634
- mockVideo.on['encrypted'](
1635
- {initDataType: 'webm', initData: initData2, keyId: null});
1592
+ await sendEncryptedEvent('webm');
1593
+ await sendEncryptedEvent('cenc', new Uint8Array(2));
1636
1594
 
1637
1595
  const message = new Uint8Array(0);
1638
1596
  session1.on['message']({target: session1, message: message});
@@ -1648,12 +1606,8 @@ describe('DrmEngine', () => {
1648
1606
 
1649
1607
  it('swallows errors when clearing MediaKeys', async () => {
1650
1608
  await initAndAttach();
1651
- const initData1 = new Uint8Array(1);
1652
- const initData2 = new Uint8Array(2);
1653
- mockVideo.on['encrypted'](
1654
- {initDataType: 'webm', initData: initData1, keyId: null});
1655
- mockVideo.on['encrypted'](
1656
- {initDataType: 'webm', initData: initData2, keyId: null});
1609
+ await sendEncryptedEvent('webm');
1610
+ await sendEncryptedEvent('cenc', new Uint8Array(2));
1657
1611
 
1658
1612
  const message = new Uint8Array(0);
1659
1613
  session1.on['message']({target: session1, message: message});
@@ -1732,6 +1686,14 @@ describe('DrmEngine', () => {
1732
1686
  const p1 = new shaka.util.PublicPromise();
1733
1687
  mockVideo.setMediaKeys.and.returnValue(p1);
1734
1688
 
1689
+ onErrorSpy.and.stub();
1690
+
1691
+ tweakDrmInfos((drmInfos) => {
1692
+ drmInfos[0].initData = [
1693
+ {initData: new Uint8Array(1), initDataType: 'cenc', keyId: null},
1694
+ ];
1695
+ });
1696
+
1735
1697
  const init = expectAsync(initAndAttach()).toBeRejected();
1736
1698
 
1737
1699
  await shaka.test.Util.shortDelay();
@@ -1745,10 +1707,12 @@ describe('DrmEngine', () => {
1745
1707
  const destroy = drmEngine.destroy();
1746
1708
  const fail = async () => {
1747
1709
  await shaka.test.Util.shortDelay();
1748
- p1.reject(new Error(''));
1710
+ shaka.log.warning('fail');
1711
+ p1.reject(new Error('titi'));
1749
1712
  };
1750
1713
  const success = async () => {
1751
1714
  await shaka.test.Util.shortDelay();
1715
+ shaka.log.warning('success');
1752
1716
  p2.resolve();
1753
1717
  };
1754
1718
  await Promise.all([init, destroy, fail(), success()]);
@@ -1760,6 +1724,12 @@ describe('DrmEngine', () => {
1760
1724
  const p1 = new shaka.util.PublicPromise();
1761
1725
  mockVideo.setMediaKeys.and.returnValue(p1);
1762
1726
 
1727
+ tweakDrmInfos((drmInfos) => {
1728
+ drmInfos[0].initData = [
1729
+ {initData: new Uint8Array(1), initDataType: 'cenc', keyId: null},
1730
+ ];
1731
+ });
1732
+
1763
1733
  const init = expectAsync(initAndAttach()).toBeRejected();
1764
1734
 
1765
1735
  await shaka.test.Util.shortDelay();
@@ -1837,9 +1807,7 @@ describe('DrmEngine', () => {
1837
1807
  session1.generateRequest.and.returnValue(p);
1838
1808
 
1839
1809
  await initAndAttach();
1840
- const initData1 = new Uint8Array(1);
1841
- mockVideo.on['encrypted'](
1842
- {initDataType: 'webm', initData: initData1, keyId: null});
1810
+ await sendEncryptedEvent();
1843
1811
 
1844
1812
  // We are now blocked on generateRequest:
1845
1813
  expect(session1.generateRequest).toHaveBeenCalledTimes(1);
@@ -1858,9 +1826,7 @@ describe('DrmEngine', () => {
1858
1826
  fakeNetEngine.request.and.returnValue(operation);
1859
1827
 
1860
1828
  await initAndAttach();
1861
- const initData1 = new Uint8Array(1);
1862
- mockVideo.on['encrypted'](
1863
- {initDataType: 'webm', initData: initData1, keyId: null});
1829
+ await sendEncryptedEvent();
1864
1830
 
1865
1831
  const message = new Uint8Array(0);
1866
1832
  session1.on['message']({target: session1, message: message});
@@ -1889,9 +1855,7 @@ describe('DrmEngine', () => {
1889
1855
  fakeNetEngine.request.and.returnValue(operation);
1890
1856
 
1891
1857
  await initAndAttach();
1892
- const initData1 = new Uint8Array(1);
1893
- mockVideo.on['encrypted'](
1894
- {initDataType: 'webm', initData: initData1, keyId: null});
1858
+ await sendEncryptedEvent();
1895
1859
 
1896
1860
  const message = new Uint8Array(0);
1897
1861
  session1.on['message']({target: session1, message: message});
@@ -1919,9 +1883,7 @@ describe('DrmEngine', () => {
1919
1883
  session1.update.and.returnValue(p);
1920
1884
 
1921
1885
  await initAndAttach();
1922
- const initData1 = new Uint8Array(1);
1923
- mockVideo.on['encrypted'](
1924
- {initDataType: 'webm', initData: initData1, keyId: null});
1886
+ await sendEncryptedEvent();
1925
1887
 
1926
1888
  const message = new Uint8Array(0);
1927
1889
  session1.on['message']({target: session1, message: message});
@@ -1955,12 +1917,8 @@ describe('DrmEngine', () => {
1955
1917
  session1.close.and.returnValue(rejected);
1956
1918
  session2.close.and.returnValue(rejected);
1957
1919
 
1958
- const initData1 = new Uint8Array(1);
1959
- const initData2 = new Uint8Array(2);
1960
- mockVideo.on['encrypted'](
1961
- {initDataType: 'webm', initData: initData1, keyId: null});
1962
- mockVideo.on['encrypted'](
1963
- {initDataType: 'webm', initData: initData2, keyId: null});
1920
+ await sendEncryptedEvent('webm');
1921
+ await sendEncryptedEvent('cenc', new Uint8Array(2));
1964
1922
 
1965
1923
  // Still resolve these since we are mocking close and closed. This
1966
1924
  // ensures DrmEngine is in the correct state.
@@ -2185,9 +2143,7 @@ describe('DrmEngine', () => {
2185
2143
  mockVideo.paused = true;
2186
2144
 
2187
2145
  await initAndAttach();
2188
- const initData = new Uint8Array(0);
2189
- mockVideo.on['encrypted'](
2190
- {initDataType: 'webm', initData: initData, keyId: null});
2146
+ await sendEncryptedEvent();
2191
2147
 
2192
2148
  const operation = shaka.util.AbortableOperation.completed({});
2193
2149
  fakeNetEngine.request.and.returnValue(operation);
@@ -2213,9 +2169,7 @@ describe('DrmEngine', () => {
2213
2169
  mockVideo.paused = true;
2214
2170
 
2215
2171
  await initAndAttach();
2216
- const initData = new Uint8Array(0);
2217
- mockVideo.on['encrypted'](
2218
- {initDataType: 'webm', initData: initData, keyId: null});
2172
+ await sendEncryptedEvent();
2219
2173
 
2220
2174
  const operation = shaka.util.AbortableOperation.completed({});
2221
2175
  fakeNetEngine.request.and.returnValue(operation);
@@ -2330,10 +2284,9 @@ describe('DrmEngine', () => {
2330
2284
  session1.expiration = NaN;
2331
2285
 
2332
2286
  await initAndAttach();
2333
- const initData = new Uint8Array(0);
2287
+ await sendEncryptedEvent();
2288
+
2334
2289
  const message = new Uint8Array(0);
2335
- mockVideo.on['encrypted'](
2336
- {initDataType: 'webm', initData: initData, keyId: null});
2337
2290
  session1.on['message']({target: session1, message: message});
2338
2291
  session1.update.and.returnValue(Promise.resolve());
2339
2292
  });
@@ -2496,4 +2449,17 @@ describe('DrmEngine', () => {
2496
2449
  callback(manifest.variants[0].audio.drmInfos);
2497
2450
  }
2498
2451
  }
2452
+
2453
+ /**
2454
+ *
2455
+ * @param {string} initDataType
2456
+ * @param {Uint8Array} initData
2457
+ * @param {string|null} keyId
2458
+ */
2459
+ async function sendEncryptedEvent(
2460
+ initDataType = 'cenc', initData = new Uint8Array(1), keyId = null) {
2461
+ mockVideo.on['encrypted']({initDataType, initData, keyId});
2462
+
2463
+ await Util.shortDelay();
2464
+ }
2499
2465
  });
@@ -103,6 +103,7 @@ describe('MediaSourceEngine', () => {
103
103
  return {
104
104
  mimeType: streamMetadata.mimeType,
105
105
  codecs: streamMetadata.codecs,
106
+ drmInfos: [],
106
107
  };
107
108
  }
108
109
 
@@ -288,7 +289,27 @@ describe('MediaSourceEngine', () => {
288
289
  await mediaSourceEngine.setStreamProperties(ContentType.VIDEO,
289
290
  /* timestampOffset= */ 0,
290
291
  /* appendWindowStart= */ 5,
291
- /* appendWindowEnd= */ 18);
292
+ /* appendWindowEnd= */ 18,
293
+ /* sequenceMode= */ false);
294
+ expect(buffered(ContentType.VIDEO, 0)).toBe(0);
295
+ await append(ContentType.VIDEO, 0);
296
+ expect(bufferStart(ContentType.VIDEO)).toBeCloseTo(5, 1);
297
+ expect(buffered(ContentType.VIDEO, 5)).toBeCloseTo(5, 1);
298
+ await append(ContentType.VIDEO, 1);
299
+ expect(buffered(ContentType.VIDEO, 5)).toBeCloseTo(13, 1);
300
+ });
301
+
302
+ it('does not initialize timestamp offset in sequence mode', async () => {
303
+ const initObject = new Map();
304
+ initObject.set(ContentType.VIDEO, getFakeStream(metadata.video));
305
+ await mediaSourceEngine.init(initObject, false);
306
+ await mediaSourceEngine.setDuration(presentationDuration);
307
+ await appendInit(ContentType.VIDEO);
308
+ await mediaSourceEngine.setStreamProperties(ContentType.VIDEO,
309
+ /* timestampOffset= */ 100,
310
+ /* appendWindowStart= */ 5,
311
+ /* appendWindowEnd= */ 18,
312
+ /* sequenceMode= */ true);
292
313
  expect(buffered(ContentType.VIDEO, 0)).toBe(0);
293
314
  await append(ContentType.VIDEO, 0);
294
315
  expect(bufferStart(ContentType.VIDEO)).toBeCloseTo(5, 1);
@@ -307,7 +328,8 @@ describe('MediaSourceEngine', () => {
307
328
  await mediaSourceEngine.setStreamProperties(ContentType.VIDEO,
308
329
  /* timestampOffset= */ 0,
309
330
  /* appendWindowStart= */ 0,
310
- /* appendWindowEnd= */ 20);
331
+ /* appendWindowEnd= */ 20,
332
+ /* sequenceMode= */ false);
311
333
  await append(ContentType.VIDEO, 0);
312
334
  await append(ContentType.VIDEO, 1);
313
335
  expect(bufferStart(ContentType.VIDEO)).toBeCloseTo(0, 1);
@@ -319,7 +341,8 @@ describe('MediaSourceEngine', () => {
319
341
  await mediaSourceEngine.setStreamProperties(ContentType.VIDEO,
320
342
  /* timestampOffset= */ 15,
321
343
  /* appendWindowStart= */ 20,
322
- /* appendWindowEnd= */ 35);
344
+ /* appendWindowEnd= */ 35,
345
+ /* sequenceMode= */ false);
323
346
  await append(ContentType.VIDEO, 0);
324
347
  await append(ContentType.VIDEO, 1);
325
348
  expect(bufferStart(ContentType.VIDEO)).toBeCloseTo(0, 1);
@@ -49,10 +49,10 @@ describe('MediaSourceEngine', () => {
49
49
  const buffer2 = /** @type {!ArrayBuffer} */ (/** @type {?} */ (2));
50
50
  const buffer3 = /** @type {!ArrayBuffer} */ (/** @type {?} */ (3));
51
51
 
52
- const fakeVideoStream = {mimeType: 'video/foo'};
53
- const fakeAudioStream = {mimeType: 'audio/foo'};
54
- const fakeTextStream = {mimeType: 'text/foo'};
55
- const fakeTransportStream = {mimeType: 'tsMimetype'};
52
+ const fakeVideoStream = {mimeType: 'video/foo', drmInfos: []};
53
+ const fakeAudioStream = {mimeType: 'audio/foo', drmInfos: []};
54
+ const fakeTextStream = {mimeType: 'text/foo', drmInfos: []};
55
+ const fakeTransportStream = {mimeType: 'tsMimetype', drmInfos: []};
56
56
 
57
57
  let audioSourceBuffer;
58
58
  let videoSourceBuffer;
@@ -812,7 +812,8 @@ describe('MediaSourceEngine', () => {
812
812
  await mediaSourceEngine.setStreamProperties(ContentType.TEXT,
813
813
  /* timestampOffset= */ 10,
814
814
  /* appendWindowStart= */ 0,
815
- /* appendWindowEnd= */ 20);
815
+ /* appendWindowEnd= */ 20,
816
+ /* sequenceMode= */ false);
816
817
  expect(mockTextEngine.setTimestampOffset).toHaveBeenCalledWith(10);
817
818
  expect(mockTextEngine.setAppendWindow).toHaveBeenCalledWith(0, 20);
818
819
  });
@@ -1107,7 +1108,7 @@ describe('MediaSourceEngine', () => {
1107
1108
  });
1108
1109
 
1109
1110
  it('destroys text engines', async () => {
1110
- mediaSourceEngine.reinitText('text/vtt');
1111
+ mediaSourceEngine.reinitText('text/vtt', false);
1111
1112
 
1112
1113
  await mediaSourceEngine.destroy();
1113
1114
  expect(mockTextEngine).toBeTruthy();