shaka-player 4.2.9 → 4.2.11

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 (92) hide show
  1. package/.github/workflows/demo-version-index.yaml +3 -3
  2. package/.github/workflows/selenium-lab-tests.yaml +23 -1
  3. package/AUTHORS +2 -1
  4. package/CHANGELOG.md +44 -0
  5. package/CONTRIBUTORS +4 -1
  6. package/README.md +3 -0
  7. package/demo/demo.less +1 -0
  8. package/dist/controls.css +1 -1
  9. package/dist/demo.compiled.debug.js +154 -276
  10. package/dist/demo.compiled.debug.map +4 -4
  11. package/dist/demo.compiled.js +154 -276
  12. package/dist/demo.compiled.map +4 -4
  13. package/dist/demo.css +1 -1
  14. package/dist/demo.css.map +1 -1
  15. package/dist/deps.js +1 -1
  16. package/dist/locales.js +33 -33
  17. package/dist/receiver.compiled.debug.js +36 -65
  18. package/dist/receiver.compiled.debug.map +4 -4
  19. package/dist/receiver.compiled.js +36 -65
  20. package/dist/receiver.compiled.map +4 -4
  21. package/dist/shaka-player.compiled.d.ts +20 -3
  22. package/dist/shaka-player.compiled.debug.d.ts +20 -3
  23. package/dist/shaka-player.compiled.debug.externs.js +26 -12
  24. package/dist/shaka-player.compiled.debug.js +185 -180
  25. package/dist/shaka-player.compiled.debug.map +4 -4
  26. package/dist/shaka-player.compiled.externs.js +26 -12
  27. package/dist/shaka-player.compiled.js +821 -818
  28. package/dist/shaka-player.compiled.map +3 -3
  29. package/dist/shaka-player.ui.d.ts +20 -3
  30. package/dist/shaka-player.ui.debug.d.ts +20 -3
  31. package/dist/shaka-player.ui.debug.externs.js +14 -0
  32. package/dist/shaka-player.ui.debug.js +266 -261
  33. package/dist/shaka-player.ui.debug.map +3 -3
  34. package/dist/shaka-player.ui.externs.js +14 -0
  35. package/dist/shaka-player.ui.js +964 -960
  36. package/dist/shaka-player.ui.map +3 -3
  37. package/docs/tutorials/a11y.md +0 -4
  38. package/docs/tutorials/ad_monetization.md +0 -4
  39. package/docs/tutorials/basic-usage.md +0 -5
  40. package/docs/tutorials/config.md +0 -5
  41. package/docs/tutorials/debugging.md +0 -5
  42. package/docs/tutorials/drm-config.md +0 -5
  43. package/docs/tutorials/fairplay.md +2 -2
  44. package/docs/tutorials/license-server-auth.md +0 -5
  45. package/docs/tutorials/license-wrapping.md +0 -5
  46. package/docs/tutorials/network-and-buffering-config.md +0 -5
  47. package/docs/tutorials/ui-customization.md +0 -5
  48. package/docs/tutorials/ui.md +0 -7
  49. package/docs/tutorials/welcome.md +1 -6
  50. package/externs/network_information.js +7 -2
  51. package/externs/shaka/abr_manager.js +6 -0
  52. package/externs/shaka/net.js +1 -0
  53. package/externs/shaka/player.js +13 -7
  54. package/lib/abr/simple_abr_manager.js +27 -3
  55. package/lib/ads/client_side_ad_manager.js +6 -3
  56. package/lib/dash/dash_parser.js +49 -48
  57. package/lib/debug/log.js +9 -13
  58. package/lib/hls/hls_parser.js +6 -0
  59. package/lib/hls/manifest_text_parser.js +10 -1
  60. package/lib/media/drm_engine.js +9 -6
  61. package/lib/media/media_source_engine.js +17 -8
  62. package/lib/media/segment_index.js +2 -0
  63. package/lib/media/segment_reference.js +22 -0
  64. package/lib/media/streaming_engine.js +17 -7
  65. package/lib/net/http_fetch_plugin.js +79 -57
  66. package/lib/net/networking_engine.js +1 -0
  67. package/lib/player.js +26 -3
  68. package/lib/polyfill/media_capabilities.js +13 -0
  69. package/lib/text/mp4_vtt_parser.js +4 -0
  70. package/lib/text/text_engine.js +1 -0
  71. package/lib/util/manifest_parser_utils.js +1 -2
  72. package/lib/util/mime_utils.js +11 -0
  73. package/lib/util/periods.js +5 -5
  74. package/lib/util/stream_utils.js +2 -2
  75. package/maintained-branches.md +3 -4
  76. package/package.json +9 -3
  77. package/test/hls/hls_live_unit.js +3 -1
  78. package/test/media/content_workarounds_unit.js +43 -0
  79. package/test/media/drm_engine_integration.js +4 -17
  80. package/test/media/media_source_engine_unit.js +31 -0
  81. package/test/media/streaming_engine_unit.js +6 -1
  82. package/test/net/networking_engine_unit.js +6 -1
  83. package/test/player_integration.js +39 -0
  84. package/test/player_unit.js +57 -0
  85. package/test/polyfill/media_capabilities_unit.js +0 -1
  86. package/test/test/assets/text-clip-alt.vtt +63 -0
  87. package/test/test/util/fake_drm_engine.js +3 -0
  88. package/test/test/util/layout_tests.js +4 -3
  89. package/test/test/util/simple_fakes.js +6 -0
  90. package/test/test/util/test_scheme.js +9 -14
  91. package/test/text/mp4_vtt_parser_unit.js +8 -0
  92. package/test/util/mime_utils_unit.js +10 -0
@@ -56,10 +56,6 @@ this.eventManager.listen(this.button_, 'click', () => {
56
56
  });
57
57
  ```
58
58
 
59
- #### Continue the Tutorials
60
-
61
- Next, check out {@tutorial ad_monetization}.
62
-
63
59
 
64
60
 
65
61
  [Web Accessibility Standards]: https://www.w3.org/WAI/standards-guidelines/wcag/
@@ -222,7 +222,3 @@ before instantiating the player.
222
222
  // myapp.CustomAdManager is a placeholder name for your ad manager implementation.
223
223
  shaka.Player.setAdManagerFactory(() => new myapp.CustomAdManager());
224
224
  ```
225
-
226
- #### Continue the Tutorials
227
-
228
- Next, check out {@tutorial plugins}.
@@ -86,8 +86,3 @@ document.addEventListener('DOMContentLoaded', initApp);
86
86
  ```
87
87
 
88
88
  That's it!
89
-
90
-
91
- #### Continue the Tutorials
92
-
93
- Next, check out {@tutorial debugging}.
@@ -142,8 +142,3 @@ player.configure({
142
142
 
143
143
  For more detail on individual configuration options, please see the API docs for
144
144
  {@link shaka.extern.PlayerConfiguration} and {@link shaka.Player#configure}.
145
-
146
-
147
- #### Continue the Tutorials
148
-
149
- Next, check out {@tutorial network-and-buffering-config}.
@@ -187,8 +187,3 @@ To sum up, remember these points when debugging your application:
187
187
  - Use the debug version of Shaka Player for debugging and integration work
188
188
  - Refer to the docs for error codes
189
189
  - Increase the log level when you need more detail
190
-
191
-
192
- #### Continue the Tutorials
193
-
194
- Next, check out {@tutorial config}.
@@ -208,8 +208,3 @@ you should provide an empty string as robustness
208
208
  ##### Other key-systems
209
209
 
210
210
  Values for other key systems are not known to us at this time.
211
-
212
- #### Continue the Tutorials
213
-
214
- Next, check out {@tutorial license-server-auth}.
215
- Or check out {@tutorial fairplay}.
@@ -65,13 +65,13 @@ is used by the browser to generate the license request. If you don't use the
65
65
  default content ID derivation, you need to specify a custom init data transform:
66
66
 
67
67
  ```js
68
- player.configure('drm.initDataTransform', (initData, initDataType) => {
68
+ player.configure('drm.initDataTransform', (initData, initDataType, drmInfo) => {
69
69
  if (initDataType != 'skd')
70
70
  return initData;
71
71
  // 'initData' is a buffer containing an 'skd://' URL as a UTF-8 string.
72
72
  const skdUri = shaka.util.StringUtils.fromBytesAutoDetect(initData);
73
73
  const contentId = getMyContentId(skdUri);
74
- const cert = player.drmInfo().serverCertificate;
74
+ const cert = drmInfo.serverCertificate;
75
75
  return shaka.util.FairPlayUtils.initDataTransform(initData, contentId, cert);
76
76
  });
77
77
  ```
@@ -246,8 +246,3 @@ License request can now continue.
246
246
 
247
247
  If you need them, you can also create asynchronous response filters in the same
248
248
  way.
249
-
250
-
251
- #### Continue the Tutorials
252
-
253
- Next, check out {@tutorial license-wrapping}.
@@ -166,8 +166,3 @@ using a request filter:
166
166
 
167
167
  Load the page again, and the license response will be accepted by the Widevine
168
168
  CDM. Open the JavaScript console to see what the server sent back.
169
-
170
-
171
- #### Continue the Tutorials
172
-
173
- Next, check out {@tutorial ui}.
@@ -117,8 +117,3 @@ URLs in your manifests always use `https:`, or by having it not include the
117
117
  scheme (e.g., `//example.com/file.mp4`).
118
118
 
119
119
  [CORS]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
120
-
121
-
122
- #### Continue the Tutorials
123
-
124
- Next, check out {@tutorial drm-config}.
@@ -265,8 +265,3 @@ PR contributions to [the gallery repo][] are welcome.
265
265
  [@lucksy]: https://github.com/lucksy
266
266
  [pre-packaged Shaka UI themes]: https://lucksy.github.io/shaka-player-themes/
267
267
  [the gallery repo]: https://github.com/lucksy/shaka-player-themes
268
-
269
-
270
- #### Continue the Tutorials
271
-
272
- Next, check out {@tutorial a11y} to make your custom buttons accessible to screen readers.
@@ -227,10 +227,3 @@ ui.configure({
227
227
  'castAndroidReceiverCompatible': true,
228
228
  });
229
229
  ```
230
-
231
-
232
-
233
-
234
- #### Continue the Tutorials
235
-
236
- Next, check out {@tutorial ui-customization}.
@@ -29,7 +29,7 @@ You can build Shaka on Linux, Windows, or Mac.
29
29
  To get the sources and compile the library, you will need:
30
30
  * {@link https://git-scm.com/downloads Git v1.9+}
31
31
  * {@link https://www.python.org/downloads/ Python v2.7 or v3.5+}
32
- * {@link https://java.com/en/download/ Java Runtime Environment v14+}
32
+ * {@link https://learn.microsoft.com/en-us/java/openjdk/download Java Runtime Environment v14+}
33
33
  * {@link https://nodejs.org/en/download/ NodeJS v14+}
34
34
  * A local web server, such as {@link https://httpd.apache.org/ Apache}
35
35
  * _NOTE: A local web server is required because browsers place restrictions
@@ -106,8 +106,3 @@ To subscribe to new releases on GitHub, you can follow
106
106
  To receive infrequent announcements and surveys from us, you can join our
107
107
  [mailing list](https://groups.google.com/forum/#!forum/shaka-player-users).
108
108
  The list is very low volume, and can only be written to by us.
109
-
110
-
111
- #### Continue the Tutorials
112
-
113
- Next, check out {@tutorial basic-usage}.
@@ -19,5 +19,10 @@ NetworkInformation.prototype.saveData;
19
19
  * @param {string} type
20
20
  * @param {Function} listener
21
21
  */
22
- NetworkInformation.prototype.addEventListener =
23
- function(type, listener) {};
22
+ NetworkInformation.prototype.addEventListener = function(type, listener) {};
23
+
24
+ /**
25
+ * @param {string} type
26
+ * @param {Function} listener
27
+ */
28
+ NetworkInformation.prototype.removeEventListener = function(type, listener) {};
@@ -44,6 +44,12 @@ shaka.extern.AbrManager = class {
44
44
  */
45
45
  stop() {}
46
46
 
47
+ /**
48
+ * Request that this object release all internal references.
49
+ * @exportDoc
50
+ */
51
+ release() {}
52
+
47
53
  /**
48
54
  * Updates manager's variants collection.
49
55
  *
@@ -112,6 +112,7 @@ shaka.extern.Request;
112
112
  /**
113
113
  * @typedef {{
114
114
  * uri: string,
115
+ * originalUri: string,
115
116
  * data: BufferSource,
116
117
  * status: (number|undefined),
117
118
  * headers: !Object.<string, string>,
@@ -627,9 +627,7 @@ shaka.extern.AdvancedDrmConfiguration;
627
627
  * clearKeys: !Object.<string, string>,
628
628
  * delayLicenseRequestUntilPlayed: boolean,
629
629
  * advanced: Object.<string, shaka.extern.AdvancedDrmConfiguration>,
630
- * initDataTransform:
631
- * ((function(!Uint8Array, string, ?shaka.extern.DrmInfo):!Uint8Array)|
632
- * undefined),
630
+ * initDataTransform:(shaka.extern.InitDataTransform|undefined),
633
631
  * logLicenseExchange: boolean,
634
632
  * updateExpirationTime: number,
635
633
  * preferredKeySystems: !Array.<string>,
@@ -655,10 +653,7 @@ shaka.extern.AdvancedDrmConfiguration;
655
653
  * <i>Optional.</i> <br>
656
654
  * A dictionary which maps key system IDs to advanced DRM configuration for
657
655
  * those key systems.
658
- * @property
659
- * {((function(!Uint8Array, string, ?shaka.extern.DrmInfo):!Uint8Array)|
660
- * undefined)}
661
- * initDataTransform
656
+ * @property {shaka.extern.InitDataTransform|undefined} initDataTransform
662
657
  * <i>Optional.</i><br>
663
658
  * If given, this function is called with the init data from the
664
659
  * manifest/media and should return the (possibly transformed) init data to
@@ -687,6 +682,17 @@ shaka.extern.AdvancedDrmConfiguration;
687
682
  */
688
683
  shaka.extern.DrmConfiguration;
689
684
 
685
+ /**
686
+ * @typedef {function(!Uint8Array, string, ?shaka.extern.DrmInfo):!Uint8Array}
687
+ *
688
+ * @description
689
+ * A callback function to handle custom content ID signaling for FairPlay
690
+ * content.
691
+ *
692
+ * @exportDoc
693
+ */
694
+ shaka.extern.InitDataTransform;
695
+
690
696
 
691
697
  /**
692
698
  * @typedef {{
@@ -6,6 +6,7 @@
6
6
 
7
7
  goog.provide('shaka.abr.SimpleAbrManager');
8
8
 
9
+ goog.require('shaka.util.IReleasable');
9
10
  goog.require('goog.asserts');
10
11
  goog.require('shaka.abr.EwmaBandwidthEstimator');
11
12
  goog.require('shaka.log');
@@ -32,6 +33,7 @@ goog.require('shaka.util.Timer');
32
33
  * </p>
33
34
  *
34
35
  * @implements {shaka.extern.AbrManager}
36
+ * @implements {shaka.util.IReleasable}
35
37
  * @export
36
38
  */
37
39
  shaka.abr.SimpleAbrManager = class {
@@ -50,8 +52,8 @@ shaka.abr.SimpleAbrManager = class {
50
52
  // retrieving information about a user's network connection. We listen
51
53
  // to the change event to be able to make quick changes in case the type
52
54
  // of connectivity changes.
53
- if (navigator.connection) {
54
- navigator.connection.addEventListener('change', () => {
55
+ if (navigator.connection && navigator.connection.addEventListener) {
56
+ this.onNetworkInformationChange_ = () => {
55
57
  if (this.config_.useNetworkInformation && this.enabled_) {
56
58
  this.bandwidthEstimator_ = new shaka.abr.EwmaBandwidthEstimator();
57
59
  if (this.config_) {
@@ -62,7 +64,10 @@ shaka.abr.SimpleAbrManager = class {
62
64
  this.switch_(chosenVariant);
63
65
  }
64
66
  }
65
- });
67
+ };
68
+
69
+ navigator.connection.addEventListener(
70
+ 'change', this.onNetworkInformationChange_);
66
71
  }
67
72
 
68
73
  /**
@@ -93,6 +98,9 @@ shaka.abr.SimpleAbrManager = class {
93
98
  /** @private {ResizeObserver} */
94
99
  this.resizeObserver_ = null;
95
100
 
101
+ /** @private {?function():void} */
102
+ this.onNetworkInformationChange_ = null;
103
+
96
104
  /** @private {shaka.util.Timer} */
97
105
  this.resizeObserverTimer_ = new shaka.util.Timer(() => {
98
106
  if (this.config_.restrictToElementSize) {
@@ -128,6 +136,22 @@ shaka.abr.SimpleAbrManager = class {
128
136
  // can start using bandwidth estimates right away after init() is called.
129
137
  }
130
138
 
139
+ /**
140
+ * @override
141
+ * @export
142
+ */
143
+ release() {
144
+ // stop() should already have been called for unload
145
+
146
+ if (navigator.connection && navigator.connection.removeEventListener) {
147
+ navigator.connection.removeEventListener(
148
+ 'change', this.onNetworkInformationChange_);
149
+ this.onNetworkInformationChange_ = null;
150
+ }
151
+
152
+ this.resizeObserverTimer_ = null;
153
+ }
154
+
131
155
 
132
156
  /**
133
157
  * @override
@@ -219,9 +219,9 @@ shaka.ads.ClientSideAdManager = class {
219
219
  // seen the ads actually play until requestAds() is called.
220
220
  // Note: We listen for a play event to avoid autoplay issues that might
221
221
  // crash IMA.
222
- this.video_.addEventListener('play', () => {
222
+ this.eventManager_.listenOnce(this.video_, 'play', () => {
223
223
  this.imaAdsManager_.start();
224
- }, {once: true});
224
+ });
225
225
  } catch (adError) {
226
226
  // If there was a problem with the VAST response,
227
227
  // we we won't be getting an ad. Hide ad UI if we showed it already
@@ -427,7 +427,10 @@ shaka.ads.ClientSideAdManager = class {
427
427
  if (this.ad_.isLinear()) {
428
428
  this.adContainer_.setAttribute('ad-active', 'true');
429
429
  this.video_.pause();
430
- this.ad_.setVolume(this.video_.muted ? 0 : this.video_.volume);
430
+ this.ad_.setVolume(this.video_.volume);
431
+ if (this.video_.muted) {
432
+ this.ad_.setMuted(true);
433
+ }
431
434
  }
432
435
  }
433
436
 
@@ -1279,55 +1279,56 @@ shaka.dash.DashParser = class {
1279
1279
  context.period.id + ',' + context.representation.id : '';
1280
1280
 
1281
1281
  /** @type {shaka.extern.Stream} */
1282
- const stream = {
1283
- id: this.globalId_++,
1284
- originalId: context.representation.id,
1285
- createSegmentIndex: async () => {
1286
- // If we have a stream with the same context id stored in the map
1287
- // that has no segmentIndex, we should set the segmentIndex for it.
1288
- const storedInMap = contextId && context.dynamic &&
1289
- this.streamMap_[contextId];
1290
-
1291
- const currentStream = storedInMap ? this.streamMap_[contextId] : stream;
1292
- if (!currentStream.segmentIndex) {
1293
- currentStream.segmentIndex = await streamInfo.generateSegmentIndex();
1294
- }
1295
- },
1282
+ let stream;
1296
1283
 
1297
- closeSegmentIndex: () => {
1298
- if (stream.segmentIndex) {
1299
- stream.segmentIndex.release();
1300
- stream.segmentIndex = null;
1301
- }
1302
- },
1303
- segmentIndex: null,
1304
- mimeType: context.representation.mimeType,
1305
- codecs: context.representation.codecs,
1306
- frameRate: context.representation.frameRate,
1307
- pixelAspectRatio: context.representation.pixelAspectRatio,
1308
- bandwidth: context.bandwidth,
1309
- width: context.representation.width,
1310
- height: context.representation.height,
1311
- kind,
1312
- encrypted: contentProtection.drmInfos.length > 0,
1313
- drmInfos: contentProtection.drmInfos,
1314
- keyIds,
1315
- language,
1316
- label,
1317
- type: context.adaptationSet.contentType,
1318
- primary: isPrimary,
1319
- trickModeVideo: null,
1320
- emsgSchemeIdUris:
1321
- context.representation.emsgSchemeIdUris,
1322
- roles,
1323
- forced: forced,
1324
- channelsCount: context.representation.numChannels,
1325
- audioSamplingRate: context.representation.audioSamplingRate,
1326
- spatialAudio: spatialAudio,
1327
- closedCaptions,
1328
- hdr,
1329
- tilesLayout,
1330
- matchedStreams: [],
1284
+ if (contextId && this.streamMap_[contextId]) {
1285
+ stream = this.streamMap_[contextId];
1286
+ } else {
1287
+ stream = {
1288
+ id: this.globalId_++,
1289
+ originalId: context.representation.id,
1290
+ createSegmentIndex: () => Promise.resolve(),
1291
+ closeSegmentIndex: () => {
1292
+ if (stream.segmentIndex) {
1293
+ stream.segmentIndex.release();
1294
+ stream.segmentIndex = null;
1295
+ }
1296
+ },
1297
+ segmentIndex: null,
1298
+ mimeType: context.representation.mimeType,
1299
+ codecs: context.representation.codecs,
1300
+ frameRate: context.representation.frameRate,
1301
+ pixelAspectRatio: context.representation.pixelAspectRatio,
1302
+ bandwidth: context.bandwidth,
1303
+ width: context.representation.width,
1304
+ height: context.representation.height,
1305
+ kind,
1306
+ encrypted: contentProtection.drmInfos.length > 0,
1307
+ drmInfos: contentProtection.drmInfos,
1308
+ keyIds,
1309
+ language,
1310
+ label,
1311
+ type: context.adaptationSet.contentType,
1312
+ primary: isPrimary,
1313
+ trickModeVideo: null,
1314
+ emsgSchemeIdUris:
1315
+ context.representation.emsgSchemeIdUris,
1316
+ roles,
1317
+ forced,
1318
+ channelsCount: context.representation.numChannels,
1319
+ audioSamplingRate: context.representation.audioSamplingRate,
1320
+ spatialAudio,
1321
+ closedCaptions,
1322
+ hdr,
1323
+ tilesLayout,
1324
+ matchedStreams: [],
1325
+ };
1326
+ }
1327
+
1328
+ stream.createSegmentIndex = async () => {
1329
+ if (!stream.segmentIndex) {
1330
+ stream.segmentIndex = await streamInfo.generateSegmentIndex();
1331
+ }
1331
1332
  };
1332
1333
 
1333
1334
  if (contextId && context.dynamic && !this.streamMap_[contextId]) {
package/lib/debug/log.js CHANGED
@@ -134,23 +134,19 @@ shaka.log.MAX_LOG_LEVEL = 3;
134
134
  shaka.log.oneTimeWarningIssued_ = new Set();
135
135
 
136
136
 
137
- // IE8 has no console unless it is opened in advance.
138
- // IE9 console methods are not Functions and have no bind.
139
- if (window.console && window.console.log.bind) {
137
+ if (window.console) {
140
138
  /** @private {!Object.<shaka.log.Level, function(...*)>} */
141
139
  shaka.log.logMap_ = {
142
- /* eslint-disable no-restricted-syntax */
143
- [shaka.log.Level.ERROR]: console.error.bind(console),
144
- [shaka.log.Level.WARNING]: console.warn.bind(console),
145
- [shaka.log.Level.INFO]: console.info.bind(console),
146
- [shaka.log.Level.DEBUG]: console.log.bind(console),
147
- [shaka.log.Level.V1]: console.debug.bind(console),
148
- [shaka.log.Level.V2]: console.debug.bind(console),
149
- /* eslint-enable no-restricted-syntax */
140
+ [shaka.log.Level.ERROR]: (...args) => console.error(...args),
141
+ [shaka.log.Level.WARNING]: (...args) => console.warn(...args),
142
+ [shaka.log.Level.INFO]: (...args) => console.info(...args),
143
+ [shaka.log.Level.DEBUG]: (...args) => console.log(...args),
144
+ [shaka.log.Level.V1]: (...args) => console.debug(...args),
145
+ [shaka.log.Level.V2]: (...args) => console.debug(...args),
150
146
  };
151
147
 
152
- shaka.log.alwaysWarn = shaka.log.logMap_[shaka.log.Level.WARNING];
153
- shaka.log.alwaysError = shaka.log.logMap_[shaka.log.Level.ERROR];
148
+ shaka.log.alwaysWarn = (...args) => console.warn(...args);
149
+ shaka.log.alwaysError = (...args) => console.error(...args);
154
150
 
155
151
  if (goog.DEBUG) {
156
152
  // Since we don't want to export shaka.log in production builds, we don't
@@ -2131,6 +2131,9 @@ shaka.hls.HlsParser = class {
2131
2131
  /* tileDuration= */ null,
2132
2132
  /* syncTime= */ null,
2133
2133
  partialStatus);
2134
+ if (item.name == 'EXT-X-PRELOAD-HINT') {
2135
+ partial.markAsPreload();
2136
+ }
2134
2137
  partialSegmentRefs.push(partial);
2135
2138
  } // for-loop of hlsSegment.partialSegments
2136
2139
  }
@@ -2451,6 +2454,9 @@ shaka.hls.HlsParser = class {
2451
2454
  * @private
2452
2455
  */
2453
2456
  variableSubstitution_(uri, variables) {
2457
+ if (!variables.size) {
2458
+ return uri;
2459
+ }
2454
2460
  let newUri = String(uri).replace(/%7B/g, '{').replace(/%7D/g, '}');
2455
2461
 
2456
2462
  const uriVariables = newUri.match(/{\$\w*}/g);
@@ -158,7 +158,15 @@ shaka.hls.ManifestTextParser = class {
158
158
  partialSegmentTags.push(tag);
159
159
  } else if (tag.name == 'EXT-X-PRELOAD-HINT') {
160
160
  if (tag.getAttributeValue('TYPE') == 'PART') {
161
- partialSegmentTags.push(tag);
161
+ // Note: BYTERANGE-START without BYTERANGE-LENGTH is being
162
+ // ignored.
163
+ if (tag.getAttributeValue('BYTERANGE-START') != null) {
164
+ if (tag.getAttributeValue('BYTERANGE-LENGTH') != null) {
165
+ partialSegmentTags.push(tag);
166
+ }
167
+ } else {
168
+ partialSegmentTags.push(tag);
169
+ }
162
170
  } else if (tag.getAttributeValue('TYPE') == 'MAP') {
163
171
  // Rename the Preload Hint tag to be a Map tag.
164
172
  tag.setName('EXT-X-MAP');
@@ -300,6 +308,7 @@ shaka.hls.ManifestTextParser.MEDIA_PLAYLIST_TAGS = [
300
308
  'EXT-X-ENDLIST',
301
309
  'EXT-X-SERVER-CONTROL',
302
310
  'EXT-X-SKIP',
311
+ 'EXT-X-PART-INF',
303
312
  ];
304
313
 
305
314
 
@@ -133,6 +133,9 @@ shaka.media.DrmEngine = class {
133
133
 
134
134
  /** @private {Promise} */
135
135
  this.mediaKeysAttached_ = null;
136
+
137
+ /** @private {?shaka.extern.InitDataOverride} */
138
+ this.manifestInitData_ = null;
136
139
  }
137
140
 
138
141
  /** @override */
@@ -480,10 +483,10 @@ shaka.media.DrmEngine = class {
480
483
  () => this.closeOpenSessions_());
481
484
  }
482
485
 
483
- const manifestInitData = this.currentDrmInfo_ ?
484
- this.currentDrmInfo_.initData.find(
486
+ this.manifestInitData_ = this.currentDrmInfo_ ?
487
+ (this.currentDrmInfo_.initData.find(
485
488
  (initDataOverride) => initDataOverride.initData.length > 0,
486
- ) : null;
489
+ ) || null) : null;
487
490
 
488
491
  /**
489
492
  * We can attach media keys before the playback actually begins when:
@@ -491,7 +494,7 @@ shaka.media.DrmEngine = class {
491
494
  * - Some initData already has been generated (through the manifest)
492
495
  * - In case of an offline session
493
496
  */
494
- if (manifestInitData ||
497
+ if (this.manifestInitData_ ||
495
498
  this.currentDrmInfo_.keySystem !== 'com.apple.fps' ||
496
499
  this.offlineSessionIds_.length) {
497
500
  await this.attachMediaKeys_();
@@ -504,7 +507,7 @@ shaka.media.DrmEngine = class {
504
507
  // Also suppress 'encrypted' events when parsing in-band ppsh
505
508
  // from media segments because that serves the same purpose as the
506
509
  // 'encrypted' events.
507
- if (!manifestInitData && !this.offlineSessionIds_.length &&
510
+ if (!this.manifestInitData_ && !this.offlineSessionIds_.length &&
508
511
  !this.config_.parseInbandPsshEnabled) {
509
512
  this.eventManager_.listen(
510
513
  this.video_, 'encrypted', (e) => this.onEncryptedEvent_(e));
@@ -2353,7 +2356,7 @@ shaka.media.DrmEngine = class {
2353
2356
  * @return {!Promise<void>}
2354
2357
  */
2355
2358
  parseInbandPssh(contentType, mediaSegment) {
2356
- if (!this.config_.parseInbandPsshEnabled) {
2359
+ if (!this.config_.parseInbandPsshEnabled || this.manifestInitData_) {
2357
2360
  return Promise.resolve();
2358
2361
  }
2359
2362
 
@@ -99,15 +99,15 @@ shaka.media.MediaSourceEngine = class {
99
99
  /** @private {!shaka.util.PublicPromise} */
100
100
  this.mediaSourceOpen_ = new shaka.util.PublicPromise();
101
101
 
102
+ /** @private {string} */
103
+ this.url_ = '';
104
+
102
105
  /** @private {MediaSource} */
103
106
  this.mediaSource_ = this.createMediaSource(this.mediaSourceOpen_);
104
107
 
105
108
  /** @type {!shaka.util.Destroyer} */
106
109
  this.destroyer_ = new shaka.util.Destroyer(() => this.doDestroy_());
107
110
 
108
- /** @private {string} */
109
- this.url_ = '';
110
-
111
111
  /** @private {boolean} */
112
112
  this.sequenceMode_ = false;
113
113
 
@@ -144,6 +144,8 @@ shaka.media.MediaSourceEngine = class {
144
144
  * @private
145
145
  */
146
146
  onSourceOpen_(p) {
147
+ goog.asserts.assert(this.url_, 'Must have object URL');
148
+
147
149
  // Release the object URL that was previously created, to prevent memory
148
150
  // leak.
149
151
  // createObjectURL creates a strong reference to the MediaSource object
@@ -192,6 +194,9 @@ shaka.media.MediaSourceEngine = class {
192
194
  'audio/mp4; codecs="ec-3"',
193
195
  'audio/mp4; codecs="opus"',
194
196
  'audio/mp4; codecs="flac"',
197
+ 'audio/mp4; codecs="dtsc"', // DTS Digital Surround
198
+ 'audio/mp4; codecs="dtse"', // DTS Express
199
+ 'audio/mp4; codecs="dtsx"', // DTS:X
195
200
  // WebM types
196
201
  'video/webm; codecs="vp8"',
197
202
  'video/webm; codecs="vp9"',
@@ -556,7 +561,8 @@ shaka.media.MediaSourceEngine = class {
556
561
  // For HLS CEA-608/708 CLOSED-CAPTIONS, text data is embedded in
557
562
  // the video stream, so textEngine may not have been initialized.
558
563
  if (!this.textEngine_) {
559
- this.reinitText('text/vtt', this.sequenceMode_);
564
+ this.reinitText(shaka.util.MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE,
565
+ this.sequenceMode_);
560
566
  }
561
567
 
562
568
  if (transmuxedData.metadata) {
@@ -584,7 +590,8 @@ shaka.media.MediaSourceEngine = class {
584
590
  data = transmuxedData.data;
585
591
  } else if (hasClosedCaptions) {
586
592
  if (!this.textEngine_) {
587
- this.reinitText('text/vtt', this.sequenceMode_);
593
+ this.reinitText(shaka.util.MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE,
594
+ this.sequenceMode_);
588
595
  }
589
596
  // If it is the init segment for closed captions, initialize the closed
590
597
  // caption parser.
@@ -705,7 +712,7 @@ shaka.media.MediaSourceEngine = class {
705
712
  this.append_(contentType, data);
706
713
  });
707
714
 
708
- if (goog.DEBUG && reference) {
715
+ if (goog.DEBUG && reference && !reference.isPreload()) {
709
716
  const bufferedAfter = this.getBuffered_(contentType);
710
717
  const newBuffered = shaka.media.TimeRangesUtils.computeAddedRange(
711
718
  bufferedBefore, bufferedAfter);
@@ -910,8 +917,10 @@ shaka.media.MediaSourceEngine = class {
910
917
  async endOfStream(reason) {
911
918
  await this.enqueueBlockingOperation_(() => {
912
919
  // If endOfStream() has already been called on the media source,
913
- // don't call it again.
914
- if (this.ended()) {
920
+ // don't call it again. Also do not call if readyState is
921
+ // 'closed' (not attached to video element) since it is not a
922
+ // valid operation.
923
+ if (this.ended() || this.mediaSource_.readyState === 'closed') {
915
924
  return;
916
925
  }
917
926
  // Tizen won't let us pass undefined, but it will let us omit the
@@ -363,6 +363,8 @@ shaka.media.SegmentIndex = class {
363
363
  lastReference.status,
364
364
  lastReference.hlsAes128Key,
365
365
  );
366
+ this.references[this.references.length - 1].discontinuitySequence =
367
+ lastReference.discontinuitySequence;
366
368
  }
367
369
 
368
370