shaka-player 2.5.1 → 2.5.5

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 (166) hide show
  1. package/.csslintrc +13 -0
  2. package/AUTHORS +3 -0
  3. package/CHANGELOG.md +156 -0
  4. package/CONTRIBUTORS +3 -0
  5. package/README.md +3 -0
  6. package/build/README.md +5 -5
  7. package/build/apps.py +3 -1
  8. package/build/build.py +5 -2
  9. package/build/check.py +17 -0
  10. package/build/compiler.py +49 -0
  11. package/build/conformance.textproto +1 -0
  12. package/build/docs.py +0 -6
  13. package/build/generateExterns.js +72 -20
  14. package/build/install-linux-prereqs.sh +4 -4
  15. package/build/shakaBuildHelpers.py +7 -8
  16. package/build/test.py +21 -9
  17. package/build/types/core +1 -0
  18. package/build/types/ui +6 -1
  19. package/demo/asset_card.js +129 -41
  20. package/demo/cast_receiver/receiver_app.css +27 -13
  21. package/demo/close_button.js +10 -15
  22. package/demo/common/asset.js +6 -6
  23. package/demo/common/assets.js +72 -14
  24. package/demo/config.js +28 -25
  25. package/demo/custom.js +20 -16
  26. package/demo/demo.less +107 -16
  27. package/demo/demo_uncompiled.js +33 -0
  28. package/demo/demo_utils.js +4 -3
  29. package/demo/front.js +12 -8
  30. package/demo/index.html +14 -17
  31. package/demo/input.js +30 -23
  32. package/demo/input_container.js +15 -11
  33. package/demo/load.js +5 -7
  34. package/demo/main.js +138 -49
  35. package/demo/search.js +40 -36
  36. package/demo/service_worker.js +1 -1
  37. package/demo/tooltip.js +16 -24
  38. package/dist/.csslintstamp +0 -0
  39. package/dist/controls.css +1 -1
  40. package/dist/controls.css.map +1 -1
  41. package/dist/demo.compiled.debug.js +165 -152
  42. package/dist/demo.compiled.debug.map +4 -4
  43. package/dist/demo.compiled.js +165 -152
  44. package/dist/demo.compiled.map +4 -4
  45. package/dist/demo.css +1 -1
  46. package/dist/demo.css.map +1 -1
  47. package/dist/deps.js +28 -11
  48. package/dist/receiver.compiled.debug.js +11 -11
  49. package/dist/receiver.compiled.debug.map +3 -3
  50. package/dist/receiver.compiled.js +11 -11
  51. package/dist/receiver.compiled.map +3 -3
  52. package/dist/shaka-player.compiled.debug.externs.js +232 -102
  53. package/dist/shaka-player.compiled.debug.js +189 -165
  54. package/dist/shaka-player.compiled.debug.map +4 -4
  55. package/dist/shaka-player.compiled.externs.js +232 -102
  56. package/dist/shaka-player.compiled.js +567 -553
  57. package/dist/shaka-player.compiled.map +4 -4
  58. package/dist/shaka-player.ui.debug.externs.js +338 -113
  59. package/dist/shaka-player.ui.debug.js +296 -276
  60. package/dist/shaka-player.ui.debug.map +4 -4
  61. package/dist/shaka-player.ui.externs.js +338 -113
  62. package/dist/shaka-player.ui.js +685 -671
  63. package/dist/shaka-player.ui.map +4 -4
  64. package/docs/tutorials/drm-config.md +1 -0
  65. package/docs/tutorials/fairplay.md +77 -0
  66. package/docs/tutorials/index.json +1 -0
  67. package/docs/tutorials/manifest-parser.md +1 -1
  68. package/docs/tutorials/ui-customization.md +5 -2
  69. package/docs/tutorials/ui.md +10 -4
  70. package/docs/tutorials/welcome.md +2 -2
  71. package/externs/mediasession.js +16 -1
  72. package/externs/shaka/net.js +14 -4
  73. package/externs/shaka/player.js +136 -90
  74. package/externs/tippy.js +30 -0
  75. package/externs/webkitmediakeys.js +4 -0
  76. package/karma.conf.js +30 -24
  77. package/lib/cast/cast_proxy.js +94 -23
  78. package/lib/cast/cast_receiver.js +8 -1
  79. package/lib/dash/content_protection.js +33 -1
  80. package/lib/dash/dash_parser.js +13 -5
  81. package/lib/hls/hls_parser.js +20 -4
  82. package/lib/media/drm_engine.js +29 -2
  83. package/lib/media/media_source_engine.js +9 -6
  84. package/lib/media/play_rate_controller.js +14 -3
  85. package/lib/media/playhead.js +8 -3
  86. package/lib/media/streaming_engine.js +68 -20
  87. package/lib/media/transmuxer.js +2 -2
  88. package/lib/media/video_wrapper.js +8 -3
  89. package/lib/net/data_uri_plugin.js +5 -2
  90. package/lib/net/http_fetch_plugin.js +3 -3
  91. package/lib/net/http_plugin_utils.js +2 -4
  92. package/lib/net/http_xhr_plugin.js +2 -2
  93. package/lib/net/networking_engine.js +1 -0
  94. package/lib/offline/offline_scheme.js +7 -2
  95. package/lib/player.js +18 -8
  96. package/lib/polyfill/input_event.js +7 -11
  97. package/lib/polyfill/mediasource.js +1 -1
  98. package/lib/polyfill/patchedmediakeys_apple.js +2 -72
  99. package/lib/text/cue.js +1 -1
  100. package/lib/text/ttml_text_parser.js +1 -1
  101. package/lib/util/config_utils.js +1 -0
  102. package/lib/util/error.js +45 -11
  103. package/lib/util/event_manager.js +211 -100
  104. package/lib/util/fairplay_utils.js +122 -0
  105. package/lib/util/i_releasable.js +1 -0
  106. package/lib/util/player_configuration.js +7 -0
  107. package/lib/util/pssh.js +41 -0
  108. package/lib/util/string_utils.js +42 -6
  109. package/lib/util/timer.js +1 -1
  110. package/package.json +33 -33
  111. package/roadmap.md +96 -0
  112. package/shaka-player.uncompiled.js +5 -1
  113. package/test/dash/dash_parser_content_protection_unit.js +35 -1
  114. package/test/dash/dash_parser_manifest_unit.js +60 -0
  115. package/test/hls/hls_live_unit.js +7 -1
  116. package/test/hls/hls_parser_unit.js +50 -0
  117. package/test/media/drm_engine_unit.js +10 -4
  118. package/test/media/media_source_engine_integration.js +12 -0
  119. package/test/media/media_source_engine_unit.js +3 -1
  120. package/test/media/playhead_unit.js +7 -5
  121. package/test/media/streaming_engine_unit.js +46 -1
  122. package/test/media/transmuxer_integration.js +13 -0
  123. package/test/net/data_uri_plugin_unit.js +13 -2
  124. package/test/net/http_plugin_unit.js +17 -12
  125. package/test/net/networking_engine_unit.js +17 -8
  126. package/test/offline/offline_scheme_unit.js +18 -8
  127. package/test/player_external.js +3 -2
  128. package/test/player_integration.js +94 -3
  129. package/test/player_src_equals_integration.js +2 -2
  130. package/test/player_unit.js +21 -8
  131. package/test/test/boot.js +20 -5
  132. package/test/test/externs/jasmine.js +48 -0
  133. package/test/test/util/expect_async_polyfill.js +145 -0
  134. package/test/test/util/fake_networking_engine.js +1 -0
  135. package/test/test/util/manifest_generator.js +2 -1
  136. package/test/test/util/test_scheme.js +34 -2
  137. package/test/test/util/ui_utils.js +41 -0
  138. package/test/test/util/util.js +16 -8
  139. package/test/ui/ui_unit.js +130 -4
  140. package/ui/audio_language_selection.js +17 -96
  141. package/ui/big_play_button.js +61 -0
  142. package/ui/controls.js +226 -335
  143. package/ui/controls.less +3 -5
  144. package/ui/element.js +24 -6
  145. package/ui/externs/ui.js +62 -9
  146. package/ui/fullscreen_button.js +2 -52
  147. package/ui/less/buttons.less +10 -16
  148. package/ui/less/containers.less +75 -20
  149. package/ui/less/general.less +18 -2
  150. package/ui/less/other_elements.less +2 -1
  151. package/ui/less/overflow_menu.less +11 -10
  152. package/ui/less/range_elements.less +12 -10
  153. package/ui/less/spinner.less +2 -0
  154. package/ui/overflow_menu.js +1 -1
  155. package/ui/pip_button.js +1 -1
  156. package/ui/{play_pause_button.js → play_button.js} +17 -47
  157. package/ui/presentation_time.js +17 -12
  158. package/ui/range_element.js +176 -0
  159. package/ui/resolution_selection.js +43 -106
  160. package/ui/seek_bar.js +204 -0
  161. package/ui/settings_menu.js +113 -0
  162. package/ui/small_play_button.js +73 -0
  163. package/ui/text_displayer.js +17 -14
  164. package/ui/text_selection.js +42 -107
  165. package/ui/ui.js +17 -40
  166. package/ui/volume_bar.js +40 -68
@@ -575,9 +575,16 @@ shaka.media.StreamingEngine.prototype.loadNewTextStream = async function(
575
575
  await this.setupStreams_(streamSet);
576
576
  if (this.destroyed_) { return; }
577
577
 
578
+ const showText = this.playerInterface_
579
+ .mediaSourceEngine
580
+ .getTextDisplayer()
581
+ .isTextVisible();
582
+
583
+ const streamText = showText || this.config_.alwaysStreamText;
584
+
578
585
  if ((this.textStreamSequenceId_ == currentSequenceId) &&
579
586
  !this.mediaStates_.has(ContentType.TEXT) &&
580
- !this.unloadingTextStream_) {
587
+ !this.unloadingTextStream_ && streamText) {
581
588
  const presentationTime = this.playerInterface_.getPresentationTime();
582
589
  const needPeriodIndex = this.findPeriodForTime_(presentationTime);
583
590
 
@@ -713,7 +720,12 @@ shaka.media.StreamingEngine.prototype.switchInternal_ = function(
713
720
  // handle a Period transition. Simply ignore the given stream, assuming that
714
721
  // Player will select the same track in onChooseStreams.
715
722
  let periodIndex = this.findPeriodContainingStream_(stream);
716
- if (clearBuffer && periodIndex != mediaState.needPeriodIndex) {
723
+ const mediaStates = Array.from(this.mediaStates_.values());
724
+ const needSamePeriod = mediaStates.every((ms) => {
725
+ return ms.needPeriodIndex == mediaState.needPeriodIndex;
726
+ });
727
+ if (clearBuffer && periodIndex != mediaState.needPeriodIndex &&
728
+ needSamePeriod) {
717
729
  shaka.log.debug('switch: switching to stream in another Period; clearing ' +
718
730
  'buffer and changing Periods');
719
731
  // handlePeriodTransition_ will be called on the next update because the
@@ -796,7 +808,13 @@ shaka.media.StreamingEngine.prototype.switchInternal_ = function(
796
808
  // Cancel the update timer, if any.
797
809
  this.cancelUpdate_(mediaState);
798
810
  // Clear right away.
799
- this.clearBuffer_(mediaState, /* flush */ true, safeMargin);
811
+ this.clearBuffer_(mediaState, /* flush */ true, safeMargin)
812
+ .catch((error) => {
813
+ if (this.playerInterface_) {
814
+ this.playerInterface_.onError(
815
+ /** @type {!shaka.util.Error} */ (error));
816
+ }
817
+ });
800
818
  }
801
819
  }
802
820
  };
@@ -972,7 +990,11 @@ shaka.media.StreamingEngine.prototype.forceClearBuffer_ = function(
972
990
  // buffer right away. Note: clearBuffer_() will schedule the next update.
973
991
  shaka.log.debug(logPrefix, 'clear: handling right now');
974
992
  this.cancelUpdate_(mediaState);
975
- this.clearBuffer_(mediaState, /* flush */ false, 0);
993
+ this.clearBuffer_(mediaState, /* flush */ false, 0).catch((error) => {
994
+ if (this.playerInterface_) {
995
+ this.playerInterface_.onError(/** @type {!shaka.util.Error} */ (error));
996
+ }
997
+ });
976
998
  };
977
999
 
978
1000
 
@@ -1287,8 +1309,11 @@ shaka.media.StreamingEngine.prototype.onUpdate_ = function(mediaState) {
1287
1309
  // forever at the end. We should only do this if the duration needs to
1288
1310
  // shrink. Growing it by less than 1ms can actually cause buffering on
1289
1311
  // replay, as in https://github.com/google/shaka-player/issues/979
1290
- let duration = this.playerInterface_.mediaSourceEngine.getDuration();
1291
- if (duration < this.manifest_.presentationTimeline.getDuration()) {
1312
+ // On some platforms, this can spuriously be 0, so ignore this case.
1313
+ // https://github.com/google/shaka-player/issues/1967,
1314
+ const duration = this.playerInterface_.mediaSourceEngine.getDuration();
1315
+ if (duration != 0 &&
1316
+ duration < this.manifest_.presentationTimeline.getDuration()) {
1292
1317
  this.manifest_.presentationTimeline.setDuration(duration);
1293
1318
  }
1294
1319
  }.bind(this));
@@ -1314,11 +1339,7 @@ shaka.media.StreamingEngine.prototype.update_ = function(mediaState) {
1314
1339
  // If it's a text stream and the original id starts with 'CC', it's CEA
1315
1340
  // closed captions. Do not schedule update for closed captions text
1316
1341
  // mediastate, since closed captions are embedded in video streams.
1317
- const isCaptionState = (state) => {
1318
- return state.type == ContentType.TEXT &&
1319
- state.stream.mimeType == shaka.util.MimeUtils.CLOSED_CAPTION_MIMETYPE;
1320
- };
1321
- if (isCaptionState(mediaState)) {
1342
+ if (shaka.media.StreamingEngine.isEmbeddedText_(mediaState)) {
1322
1343
  this.playerInterface_.mediaSourceEngine.setSelectedClosedCaptionId(
1323
1344
  mediaState.stream.originalId || '');
1324
1345
  return null;
@@ -1418,7 +1439,9 @@ shaka.media.StreamingEngine.prototype.update_ = function(mediaState) {
1418
1439
  mediaStates.forEach((otherState) => {
1419
1440
  // Do not consider embedded captions in this calculation. It could lead
1420
1441
  // to hangs in streaming.
1421
- if (isCaptionState(otherState)) return;
1442
+ if (shaka.media.StreamingEngine.isEmbeddedText_(otherState)) {
1443
+ return;
1444
+ }
1422
1445
 
1423
1446
  const timeNeeded = this.getTimeNeeded_(otherState, presentationTime);
1424
1447
  minTimeNeeded = Math.min(minTimeNeeded, timeNeeded);
@@ -1436,10 +1459,11 @@ shaka.media.StreamingEngine.prototype.update_ = function(mediaState) {
1436
1459
  }
1437
1460
 
1438
1461
  mediaState.resumeAt = 0;
1439
- this.fetchAndAppend_(mediaState,
1440
- presentationTime,
1441
- currentPeriodIndex,
1442
- reference);
1462
+ this.fetchAndAppend_(
1463
+ mediaState,
1464
+ presentationTime,
1465
+ currentPeriodIndex,
1466
+ reference);
1443
1467
  return null;
1444
1468
  };
1445
1469
 
@@ -2173,13 +2197,15 @@ shaka.media.StreamingEngine.prototype.handlePeriodTransition_ = function(
2173
2197
  goog.asserts.assert(
2174
2198
  mediaStates.every(function(ms) {
2175
2199
  return ms.needPeriodIndex == needPeriodIndex || ms.hasError ||
2176
- !shaka.media.StreamingEngine.isIdle_(ms);
2200
+ !shaka.media.StreamingEngine.isIdle_(ms) ||
2201
+ shaka.media.StreamingEngine.isEmbeddedText_(ms);
2177
2202
  }),
2178
2203
  'All MediaStates should need the same Period or be performing updates.');
2179
2204
 
2180
2205
  // Only call onChooseStreams() when all MediaStates need the same Period.
2181
2206
  let needSamePeriod = mediaStates.every(function(ms) {
2182
- return ms.needPeriodIndex == needPeriodIndex;
2207
+ return ms.needPeriodIndex == needPeriodIndex ||
2208
+ shaka.media.StreamingEngine.isEmbeddedText_(ms);
2183
2209
  });
2184
2210
  if (!needSamePeriod) {
2185
2211
  shaka.log.debug(
@@ -2213,6 +2239,10 @@ shaka.media.StreamingEngine.prototype.handlePeriodTransition_ = function(
2213
2239
  let allReady = mediaStates.every(function(ms) {
2214
2240
  let isIdle = shaka.media.StreamingEngine.isIdle_(ms);
2215
2241
  let currentPeriodIndex = this.findPeriodContainingStream_(ms.stream);
2242
+ if (shaka.media.StreamingEngine.isEmbeddedText_(ms)) {
2243
+ // Embedded text tracks don't do Period transitions.
2244
+ return true;
2245
+ }
2216
2246
  return isIdle && ms.needPeriodIndex == needPeriodIndex &&
2217
2247
  currentPeriodIndex != needPeriodIndex;
2218
2248
  }.bind(this));
@@ -2299,6 +2329,18 @@ shaka.media.StreamingEngine.prototype.handlePeriodTransition_ = function(
2299
2329
  };
2300
2330
 
2301
2331
 
2332
+ /**
2333
+ * @param {shaka.media.StreamingEngine.MediaState_} mediaState
2334
+ * @return {boolean}
2335
+ * @private
2336
+ */
2337
+ shaka.media.StreamingEngine.isEmbeddedText_ = function(mediaState) {
2338
+ const MimeUtils = shaka.util.MimeUtils;
2339
+ return mediaState.type == shaka.util.ManifestParserUtils.ContentType.TEXT &&
2340
+ mediaState.stream.mimeType == MimeUtils.CLOSED_CAPTION_MIMETYPE;
2341
+ };
2342
+
2343
+
2302
2344
  /**
2303
2345
  * @param {shaka.media.StreamingEngine.MediaState_} mediaState
2304
2346
  * @return {boolean} True if the given MediaState is idle; otherwise, return
@@ -2481,8 +2523,14 @@ shaka.media.StreamingEngine.prototype.scheduleUpdate_ = function(
2481
2523
  goog.asserts.assert(mediaState.updateTimer == null,
2482
2524
  logPrefix + ' did not expect update to be scheduled');
2483
2525
 
2484
- mediaState.updateTimer = new shaka.util.DelayedTick(() => {
2485
- this.onUpdate_(mediaState);
2526
+ mediaState.updateTimer = new shaka.util.DelayedTick(async () => {
2527
+ try {
2528
+ await this.onUpdate_(mediaState);
2529
+ } catch (error) {
2530
+ if (this.playerInterface_) {
2531
+ this.playerInterface_.onError(error);
2532
+ }
2533
+ }
2486
2534
  }).tickAfter(delay);
2487
2535
  };
2488
2536
 
@@ -94,7 +94,7 @@ shaka.media.Transmuxer.isSupported = function(mimeType, contentType) {
94
94
  * @return {boolean}
95
95
  */
96
96
  shaka.media.Transmuxer.isTsContainer = function(mimeType) {
97
- return mimeType.split(';')[0].split('/')[1] == 'mp2t';
97
+ return mimeType.toLowerCase().split(';')[0].split('/')[1] == 'mp2t';
98
98
  };
99
99
 
100
100
 
@@ -106,7 +106,7 @@ shaka.media.Transmuxer.isTsContainer = function(mimeType) {
106
106
  */
107
107
  shaka.media.Transmuxer.convertTsCodecs = function(contentType, tsMimeType) {
108
108
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
109
- let mp4MimeType = tsMimeType.replace('mp2t', 'mp4');
109
+ let mp4MimeType = tsMimeType.replace(/mp2t/i, 'mp4');
110
110
  if (contentType == ContentType.AUDIO) {
111
111
  mp4MimeType = mp4MimeType.replace('video', 'audio');
112
112
  }
@@ -49,6 +49,9 @@ shaka.media.VideoWrapper = function(video, onSeek, startTime) {
49
49
  /** @private {number} */
50
50
  this.startTime_ = startTime;
51
51
 
52
+ /** @private {boolean} */
53
+ this.started_ = false;
54
+
52
55
  /** @private {shaka.util.EventManager} */
53
56
  this.eventManager_ = new shaka.util.EventManager();
54
57
 
@@ -92,9 +95,7 @@ shaka.media.VideoWrapper.prototype.release = function() {
92
95
  * @return {number}
93
96
  */
94
97
  shaka.media.VideoWrapper.prototype.getTime = function() {
95
- return this.video_.readyState > 0 ?
96
- this.video_.currentTime :
97
- this.startTime_;
98
+ return this.started_ ? this.video_.currentTime : this.startTime_;
98
99
  };
99
100
 
100
101
 
@@ -186,6 +187,10 @@ shaka.media.VideoWrapper.prototype.startListeningToSeeks_ = function() {
186
187
  this.video_.readyState > 0,
187
188
  'The media element should be ready before we listen for seeking.');
188
189
 
190
+ // Now that any startup seeking is complete, we can trust the video element
191
+ // for currentTime.
192
+ this.started_ = true;
193
+
189
194
  this.eventManager_.listen(this.video_, 'seeking', () => this.onSeek_());
190
195
  };
191
196
 
@@ -31,17 +31,20 @@ goog.require('shaka.util.Uint8ArrayUtils');
31
31
  * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs
32
32
  * @param {string} uri
33
33
  * @param {shaka.extern.Request} request
34
- * @param {shaka.net.NetworkingEngine.RequestType=} requestType
34
+ * @param {shaka.net.NetworkingEngine.RequestType} requestType
35
+ * @param {shaka.extern.ProgressUpdated} progressUpdated Called when a
36
+ * progress event happened.
35
37
  * @return {!shaka.extern.IAbortableOperation.<shaka.extern.Response>}
36
38
  * @export
37
39
  */
38
- shaka.net.DataUriPlugin = function(uri, request, requestType) {
40
+ shaka.net.DataUriPlugin = function(uri, request, requestType, progressUpdated) {
39
41
  try {
40
42
  let parsed = shaka.net.DataUriPlugin.parse(uri);
41
43
 
42
44
  /** @type {shaka.extern.Response} */
43
45
  let response = {
44
46
  uri: uri,
47
+ originalUri: uri,
45
48
  data: parsed.data,
46
49
  headers: {
47
50
  'content-type': parsed.contentType,
@@ -32,8 +32,8 @@ goog.require('shaka.util.Timer');
32
32
  * @param {string} uri
33
33
  * @param {shaka.extern.Request} request
34
34
  * @param {shaka.net.NetworkingEngine.RequestType} requestType
35
- * @param {shaka.extern.ProgressUpdated=} progressUpdated Called when a progress
36
- * event happened.
35
+ * @param {shaka.extern.ProgressUpdated} progressUpdated Called when a progress
36
+ * event happened.
37
37
  * @return {!shaka.extern.IAbortableOperation.<shaka.extern.Response>}
38
38
  * @export
39
39
  */
@@ -98,7 +98,7 @@ shaka.net.HttpFetchPlugin = function(
98
98
  * @param {shaka.net.NetworkingEngine.RequestType} requestType
99
99
  * @param {!RequestInit} init
100
100
  * @param {shaka.net.HttpFetchPlugin.AbortStatus} abortStatus
101
- * @param {shaka.extern.ProgressUpdated=} progressUpdated
101
+ * @param {shaka.extern.ProgressUpdated} progressUpdated
102
102
  * @return {!Promise<!shaka.extern.Response>}
103
103
  * @private
104
104
  */
@@ -42,12 +42,10 @@ shaka.net.HttpPluginUtils.makeResponse =
42
42
  function(headers, data, status, uri, responseURL, requestType) {
43
43
  if (status >= 200 && status <= 299 && status != 202) {
44
44
  // Most 2xx HTTP codes are success cases.
45
- if (responseURL) {
46
- uri = responseURL;
47
- }
48
45
  /** @type {shaka.extern.Response} */
49
46
  let response = {
50
- uri: uri,
47
+ uri: responseURL || uri,
48
+ originalUri: uri,
51
49
  data: data,
52
50
  headers: headers,
53
51
  fromCache: !!headers['x-shaka-from-cache'],
@@ -30,8 +30,8 @@ goog.require('shaka.util.Error');
30
30
  * @param {string} uri
31
31
  * @param {shaka.extern.Request} request
32
32
  * @param {shaka.net.NetworkingEngine.RequestType} requestType
33
- * @param {shaka.extern.ProgressUpdated=} progressUpdated Called when a
34
- * progress event happened.
33
+ * @param {shaka.extern.ProgressUpdated} progressUpdated Called when a
34
+ * progress event happened.
35
35
  * @return {!shaka.extern.IAbortableOperation.<shaka.extern.Response>}
36
36
  * @export
37
37
  */
@@ -282,6 +282,7 @@ shaka.net.NetworkingEngine.makeRequest = function(uris, retryParams) {
282
282
  allowCrossSiteCredentials: false,
283
283
  retryParameters: retryParams,
284
284
  licenseRequestType: null,
285
+ sessionId: null,
285
286
  };
286
287
  };
287
288
 
@@ -30,11 +30,14 @@ goog.require('shaka.util.Error');
30
30
  * @summary A plugin that handles requests for offline content.
31
31
  * @param {string} uri
32
32
  * @param {shaka.extern.Request} request
33
- * @param {shaka.net.NetworkingEngine.RequestType=} requestType
33
+ * @param {shaka.net.NetworkingEngine.RequestType} requestType
34
+ * @param {shaka.extern.ProgressUpdated} progressUpdated Called when a
35
+ * progress event happened.
34
36
  * @return {!shaka.extern.IAbortableOperation.<shaka.extern.Response>}
35
37
  * @export
36
38
  */
37
- shaka.offline.OfflineScheme = function(uri, request, requestType) {
39
+ shaka.offline.OfflineScheme = function(
40
+ uri, request, requestType, progressUpdated) {
38
41
  let offlineUri = shaka.offline.OfflineUri.parse(uri);
39
42
 
40
43
  if (offlineUri && offlineUri.isManifest()) {
@@ -64,6 +67,7 @@ shaka.offline.OfflineScheme.getManifest_ = function(uri) {
64
67
  /** @type {shaka.extern.Response} */
65
68
  let response = {
66
69
  uri: uri,
70
+ originalUri: uri,
67
71
  data: new ArrayBuffer(0),
68
72
  headers: {'content-type': 'application/x-offline-manifest'},
69
73
  };
@@ -95,6 +99,7 @@ shaka.offline.OfflineScheme.getSegment_ = function(id, uri) {
95
99
 
96
100
  return {
97
101
  uri: uri,
102
+ originalUri: uri,
98
103
  data: segment.data,
99
104
  headers: {},
100
105
  };
package/lib/player.js CHANGED
@@ -429,7 +429,7 @@ shaka.Player.prototype.destroy = async function() {
429
429
  * @define {string} A version number taken from git at compile time.
430
430
  * @export
431
431
  */
432
- shaka.Player.version = 'v2.5.1-uncompiled';
432
+ shaka.Player.version = 'v2.5.5-uncompiled';
433
433
 
434
434
  // Initialize the deprecation system using the version string we just set
435
435
  // on the player.
@@ -1213,7 +1213,6 @@ shaka.Player.prototype.onUnload_ = async function(has, wants) {
1213
1213
 
1214
1214
  // Remove everything that has to do with loading content from our payload
1215
1215
  // since we are releasing everything that depended on it.
1216
- has.currentTime = null;
1217
1216
  has.factory = null;
1218
1217
  has.mimeType = null;
1219
1218
  has.startTime = null;
@@ -1729,7 +1728,8 @@ shaka.Player.prototype.onLoad_ = async function(has, wants) {
1729
1728
  // active one, update abr manager with filtered variants for the current
1730
1729
  // period.
1731
1730
  /** @type {shaka.extern.Period} */
1732
- const currentPeriod = this.getPresentationPeriod_();
1731
+ const currentPeriod =
1732
+ this.getPresentationPeriod_() || this.manifest_.periods[0];
1733
1733
  const hasPrimary = currentPeriod.variants.some((v) => v.primary);
1734
1734
 
1735
1735
  if (!this.config_.preferredAudioLanguage && !hasPrimary) {
@@ -2738,12 +2738,15 @@ shaka.Player.prototype.trickPlay = function(rate) {
2738
2738
  return;
2739
2739
  }
2740
2740
 
2741
- if (this.loadMode_ == shaka.Player.LoadMode.SRC_EQUALS) {
2742
- this.playRateController_.set(rate);
2741
+ if (this.video_.paused) {
2742
+ // Our fast forward is implemented with playbackRate and needs the video to
2743
+ // be playing (to not be paused) to take immediate effect.
2744
+ // If the video is paused, "unpause" it.
2745
+ this.video_.play();
2743
2746
  }
2747
+ this.playRateController_.set(rate);
2744
2748
 
2745
2749
  if (this.loadMode_ == shaka.Player.LoadMode.MEDIA_SOURCE) {
2746
- this.playRateController_.set(rate);
2747
2750
  this.streamingEngine_.setTrickPlay(Math.abs(rate) > 1);
2748
2751
  }
2749
2752
  };
@@ -3120,8 +3123,15 @@ shaka.Player.prototype.selectTextLanguage = function(language, role) {
3120
3123
 
3121
3124
  this.currentTextLanguage_ = language;
3122
3125
  this.currentTextRole_ = role || '';
3123
- // TODO: Refactor to only change text and not affect audio.
3124
- this.chooseStreamsAndSwitch_(period);
3126
+
3127
+ const chosenText = this.chooseTextStream_(period.textStreams);
3128
+ if (chosenText) {
3129
+ this.addTextStreamToSwitchHistory_(
3130
+ period, chosenText, /* fromAdaptation= */ false);
3131
+ if (this.shouldStreamText_()) {
3132
+ this.switchTextStream_(chosenText);
3133
+ }
3134
+ }
3125
3135
  } else {
3126
3136
  const track = this.getTextTracks().filter((t) => t.language == language)[0];
3127
3137
  if (track) {
@@ -42,15 +42,18 @@ shaka.polyfill.InputEvent.install = function() {
42
42
  return;
43
43
  }
44
44
 
45
- if (HTMLInputElement.prototype.addEventListener ==
46
- shaka.polyfill.InputEvent.addEventListener_) {
45
+ // In our tests, we can end up with multiple independent "shaka" namespaces.
46
+ // So we can't compare addEventListener with the polyfill directly.
47
+ // Instead, store the original in a globally accessible place and check if
48
+ // that has been used yet.
49
+ if (HTMLInputElement.prototype['originalAddEventListener']) {
47
50
  // The polyfill was already installed.
48
51
  return;
49
52
  }
50
53
 
51
54
  shaka.log.info('Patching input event support on IE.');
52
55
 
53
- shaka.polyfill.InputEvent.originalAddEventListener_ =
56
+ HTMLInputElement.prototype['originalAddEventListener'] =
54
57
  HTMLInputElement.prototype.addEventListener;
55
58
 
56
59
  HTMLInputElement.prototype['addEventListener'] =
@@ -58,13 +61,6 @@ shaka.polyfill.InputEvent.install = function() {
58
61
  };
59
62
 
60
63
 
61
- /**
62
- * The original addEventListener from HTMLInputElement.
63
- * @private Function
64
- */
65
- shaka.polyfill.InputEvent.originalAddEventListener_;
66
-
67
-
68
64
  /**
69
65
  * Add an event listener to this object and translate the event types to those
70
66
  * that work on IE11.
@@ -89,7 +85,7 @@ shaka.polyfill.InputEvent.addEventListener_ =
89
85
  }
90
86
  }
91
87
 
92
- shaka.polyfill.InputEvent.originalAddEventListener_.call(
88
+ HTMLInputElement.prototype['originalAddEventListener'].call(
93
89
  this, type, listener, options);
94
90
  };
95
91
 
@@ -277,7 +277,7 @@ shaka.polyfill.MediaSource.rejectTsContent_ = function() {
277
277
  let basicMimeType = pieces[0];
278
278
  let container = basicMimeType.split('/')[1];
279
279
 
280
- if (container == 'mp2t') {
280
+ if (container.toLowerCase() == 'mp2t') {
281
281
  return false;
282
282
  }
283
283
 
@@ -17,7 +17,6 @@
17
17
 
18
18
  goog.provide('shaka.polyfill.PatchedMediaKeysApple');
19
19
 
20
- goog.require('goog.Uri');
21
20
  goog.require('goog.asserts');
22
21
  goog.require('shaka.log');
23
22
  goog.require('shaka.polyfill.register');
@@ -25,7 +24,6 @@ goog.require('shaka.util.EventManager');
25
24
  goog.require('shaka.util.FakeEvent');
26
25
  goog.require('shaka.util.FakeEventTarget');
27
26
  goog.require('shaka.util.PublicPromise');
28
- goog.require('shaka.util.StringUtils');
29
27
  goog.require('shaka.util.Uint8ArrayUtils');
30
28
 
31
29
 
@@ -455,6 +453,7 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype.
455
453
  // initData into a Uint8Array.
456
454
  this.nativeMediaKeySession_ = this.nativeMediaKeys_.createSession(
457
455
  'video/mp4', new Uint8Array(initData));
456
+ this.sessionId = this.nativeMediaKeySession_.sessionId || '';
458
457
 
459
458
  // Attach session event handlers here.
460
459
  this.eventManager_.listen(this.nativeMediaKeySession_, 'webkitkeymessage',
@@ -533,71 +532,6 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession.prototype.
533
532
  };
534
533
 
535
534
 
536
- /**
537
- * Rebuild FairPlay init data according to Apple's docs. It's unclear why this
538
- * is not done by the browser, or if the unprefixed version will do it for us.
539
- *
540
- * @param {BufferSource} initData
541
- * @param {BufferSource} certificate
542
- * @return {BufferSource}
543
- */
544
- shaka.polyfill.PatchedMediaKeysApple.rebuildInitData_ =
545
- function(initData, certificate) {
546
- // TODO: Move this into DrmEngine if it is still needed with unprefixed EME.
547
- // FairPlay init data is in two parts and must be processed a bit.
548
- // The first part is a 4 byte little-endian int, which is the length of the
549
- // second part.
550
- const initDataArray = new Uint8Array(initData);
551
- const dataview = new DataView(initDataArray.buffer);
552
- const length = dataview.getUint32(
553
- /* position= */ 0, /* littleEndian= */ true);
554
- if (length + 4 != initDataArray.byteLength) {
555
- throw new Error('Malformed init data!');
556
- }
557
-
558
- // The second part is a UTF-16 LE URI from the manifest.
559
- const uriString = shaka.util.StringUtils.fromUTF16(
560
- initDataArray.slice(4), /* littleEndian= */ true);
561
-
562
- // The domain of that URI is the content ID according to Apple's FPS sample.
563
- const uri = new goog.Uri(uriString);
564
- const contentId = uri.getDomain();
565
-
566
- // From that, we build a new init data to use in the session. This is
567
- // composed of several parts. First, the raw init data we already got.
568
- // Second, a 4-byte LE length followed by the content ID in UTF-16-LE.
569
- // Third, a 4-byte LE length followed by the certificate.
570
- const contentIdArray = new Uint8Array(
571
- shaka.util.StringUtils.toUTF16(contentId, /* littleEndian= */ true));
572
-
573
- const rebuiltInitData = new Uint8Array(
574
- initDataArray.byteLength +
575
- 4 + contentIdArray.byteLength +
576
- 4 + certificate.byteLength);
577
-
578
- let offset = 0;
579
- /** @param {!Uint8Array} array */
580
- const append = (array) => {
581
- rebuiltInitData.set(array, offset);
582
- offset += array.byteLength;
583
- };
584
- /** @param {!Uint8Array} array */
585
- const appendWithLength = (array) => {
586
- const view = new DataView(rebuiltInitData.buffer);
587
- const value = array.byteLength;
588
- view.setUint32(offset, value, /* littleEndian= */ true);
589
- offset += 4;
590
- append(array);
591
- };
592
-
593
- append(initDataArray);
594
- appendWithLength(contentIdArray);
595
- appendWithLength(new Uint8Array(certificate));
596
-
597
- return rebuiltInitData;
598
- };
599
-
600
-
601
535
  /**
602
536
  * Handler for the native media elements webkitneedkey event.
603
537
  *
@@ -617,16 +551,12 @@ shaka.polyfill.PatchedMediaKeysApple.onWebkitNeedKey_ = function(event) {
617
551
 
618
552
  goog.asserts.assert(event.initData != null, 'missing init data!');
619
553
 
620
- const certificate = mediaKeys.certificate;
621
- goog.asserts.assert(certificate != null, 'missing certificate!');
622
-
623
554
  // NOTE: Because "this" is a real EventTarget, the event we dispatch here must
624
555
  // also be a real Event.
625
556
  const event2 = new Event('encrypted');
626
557
  // TODO: validate this initDataType against the unprefixed version
627
558
  event2.initDataType = 'cenc';
628
- event2.initData = PatchedMediaKeysApple.rebuildInitData_(
629
- event.initData, certificate);
559
+ event2.initData = event.initData;
630
560
 
631
561
  this.dispatchEvent(event2);
632
562
  };
package/lib/text/cue.js CHANGED
@@ -141,7 +141,7 @@ shaka.text.Cue = function(startTime, endTime, payload) {
141
141
  * @override
142
142
  * @exportInterface
143
143
  */
144
- this.backgroundImage = null;
144
+ this.backgroundImage = '';
145
145
 
146
146
  /**
147
147
  * @override
@@ -594,7 +594,7 @@ shaka.text.TtmlTextParser.addStyle_ = function(
594
594
  if (imageElement) {
595
595
  const backgroundImageType = imageElement.getAttribute('imagetype');
596
596
  const backgroundImageEncoding = imageElement.getAttribute('encoding');
597
- const backgroundImageData = imageElement.textContent;
597
+ const backgroundImageData = imageElement.textContent.trim();
598
598
  if (backgroundImageType == 'PNG' &&
599
599
  backgroundImageEncoding == 'Base64' &&
600
600
  backgroundImageData) {
@@ -108,6 +108,7 @@ shaka.util.ConfigUtils.mergeConfigObjects =
108
108
  * @param {string} fieldName
109
109
  * @param {*} value
110
110
  * @return {!Object}
111
+ * @export
111
112
  */
112
113
  shaka.util.ConfigUtils.convertToConfigObject = function(fieldName, value) {
113
114
  const configObject = {};