shaka-player 3.1.4 → 3.3.0

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 (214) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
  3. package/.github/ISSUE_TEMPLATE/question.md +1 -1
  4. package/AUTHORS +6 -5
  5. package/CHANGELOG.md +363 -0
  6. package/CONTRIBUTORS +4 -2
  7. package/README.md +4 -4
  8. package/build/types/core +3 -0
  9. package/build/types/offline +1 -0
  10. package/build/types/polyfill +2 -0
  11. package/build/types/ui +2 -0
  12. package/demo/common/asset.js +9 -7
  13. package/demo/common/assets.js +28 -1
  14. package/demo/common/message_ids.js +15 -2
  15. package/demo/config.js +35 -2
  16. package/demo/index.html +1 -1
  17. package/demo/locales/en.json +14 -1
  18. package/demo/locales/source.json +56 -4
  19. package/demo/main.js +2 -1
  20. package/dist/controls.css +26 -2
  21. package/dist/controls.css.map +1 -1
  22. package/dist/demo.compiled.debug.js +24 -21
  23. package/dist/demo.compiled.debug.map +3 -3
  24. package/dist/demo.compiled.js +24 -21
  25. package/dist/demo.compiled.map +3 -3
  26. package/dist/deps.js +33 -25
  27. package/dist/locales.js +31 -29
  28. package/dist/receiver.compiled.debug.js +14 -12
  29. package/dist/receiver.compiled.debug.map +3 -3
  30. package/dist/receiver.compiled.js +14 -12
  31. package/dist/receiver.compiled.map +3 -3
  32. package/dist/shaka-player.compiled.d.ts +258 -20
  33. package/dist/shaka-player.compiled.debug.d.ts +258 -20
  34. package/dist/shaka-player.compiled.debug.externs.js +1005 -695
  35. package/dist/shaka-player.compiled.debug.js +720 -640
  36. package/dist/shaka-player.compiled.debug.map +4 -4
  37. package/dist/shaka-player.compiled.externs.js +1005 -695
  38. package/dist/shaka-player.compiled.js +850 -817
  39. package/dist/shaka-player.compiled.map +4 -4
  40. package/dist/shaka-player.ui.d.ts +274 -21
  41. package/dist/shaka-player.ui.debug.d.ts +274 -21
  42. package/dist/shaka-player.ui.debug.externs.js +766 -429
  43. package/dist/shaka-player.ui.debug.js +863 -765
  44. package/dist/shaka-player.ui.debug.map +4 -4
  45. package/dist/shaka-player.ui.externs.js +766 -429
  46. package/dist/shaka-player.ui.js +1042 -996
  47. package/dist/shaka-player.ui.map +4 -4
  48. package/docs/design/bg-fetch-after.gv +29 -0
  49. package/docs/design/bg-fetch-after.gv.png +0 -0
  50. package/docs/design/bg-fetch-before.gv +18 -0
  51. package/docs/design/bg-fetch-before.gv.png +0 -0
  52. package/docs/design/bg-fetch.md +134 -0
  53. package/docs/tutorials/blob-url.md +15 -0
  54. package/docs/tutorials/index.json +1 -0
  55. package/docs/tutorials/ui-customization.md +66 -0
  56. package/docs/tutorials/ui.md +5 -5
  57. package/externs/aria.js +6 -0
  58. package/externs/ima.js +3 -0
  59. package/externs/shaka/ads.js +29 -1
  60. package/externs/shaka/manifest.js +18 -2
  61. package/externs/shaka/manifest_parser.js +10 -1
  62. package/externs/shaka/net.js +20 -4
  63. package/externs/shaka/offline.js +36 -2
  64. package/externs/shaka/player.js +182 -13
  65. package/externs/shaka/text.js +24 -10
  66. package/externs/texttrack.js +3 -0
  67. package/externs/webcrypto.js +18 -0
  68. package/lib/abr/ewma.js +14 -0
  69. package/lib/abr/ewma_bandwidth_estimator.js +16 -2
  70. package/lib/abr/simple_abr_manager.js +6 -0
  71. package/lib/ads/ad_manager.js +16 -15
  72. package/lib/ads/client_side_ad.js +8 -0
  73. package/lib/ads/client_side_ad_manager.js +14 -6
  74. package/lib/ads/server_side_ad.js +7 -0
  75. package/lib/ads/server_side_ad_manager.js +19 -2
  76. package/lib/cast/cast_proxy.js +8 -0
  77. package/lib/cast/cast_utils.js +7 -1
  78. package/lib/cea/cea608_data_channel.js +56 -56
  79. package/lib/cea/cea608_memory.js +33 -33
  80. package/lib/cea/cea708_service.js +43 -43
  81. package/lib/cea/cea708_window.js +38 -38
  82. package/lib/cea/cea_decoder.js +13 -14
  83. package/lib/cea/cea_utils.js +23 -23
  84. package/lib/cea/dtvcc_packet_builder.js +7 -7
  85. package/lib/cea/i_caption_decoder.js +2 -3
  86. package/lib/cea/i_cea_parser.js +2 -2
  87. package/lib/cea/mp4_cea_parser.js +6 -6
  88. package/lib/dash/dash_parser.js +53 -14
  89. package/lib/dash/segment_base.js +25 -1
  90. package/lib/dash/segment_list.js +18 -9
  91. package/lib/dash/segment_template.js +23 -10
  92. package/lib/hls/hls_parser.js +210 -30
  93. package/lib/media/closed_caption_parser.js +1 -2
  94. package/lib/media/drm_engine.js +162 -192
  95. package/lib/media/quality_observer.js +291 -0
  96. package/lib/media/segment_index.js +9 -1
  97. package/lib/media/segment_reference.js +37 -5
  98. package/lib/media/streaming_engine.js +48 -10
  99. package/lib/net/http_fetch_plugin.js +31 -11
  100. package/lib/net/http_plugin_utils.js +1 -0
  101. package/lib/net/http_xhr_plugin.js +40 -14
  102. package/lib/net/networking_engine.js +82 -18
  103. package/lib/offline/download_info.js +68 -0
  104. package/lib/offline/download_manager.js +14 -7
  105. package/lib/offline/indexeddb/base_storage_cell.js +35 -0
  106. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  107. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  108. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  109. package/lib/offline/indexeddb/v5_storage_cell.js +5 -0
  110. package/lib/offline/manifest_converter.js +3 -1
  111. package/lib/offline/storage.js +404 -297
  112. package/lib/offline/stored_content_utils.js +2 -0
  113. package/lib/player.js +622 -153
  114. package/lib/polyfill/aria.js +82 -0
  115. package/lib/polyfill/random_uuid.js +52 -0
  116. package/lib/routing/walker.js +2 -3
  117. package/lib/text/cue.js +12 -0
  118. package/lib/text/srt_text_parser.js +4 -4
  119. package/lib/text/text_engine.js +2 -2
  120. package/lib/text/ttml_text_parser.js +25 -2
  121. package/lib/text/ui_text_displayer.js +2 -2
  122. package/lib/text/vtt_text_parser.js +2 -2
  123. package/lib/text/web_vtt_generator.js +55 -12
  124. package/lib/util/cmcd_manager.js +826 -0
  125. package/lib/util/error.js +12 -0
  126. package/lib/util/language_utils.js +12 -0
  127. package/lib/util/manifest_parser_utils.js +1 -0
  128. package/lib/util/mp4_box_parsers.js +20 -20
  129. package/lib/util/multi_map.js +8 -0
  130. package/lib/util/mutex.js +52 -0
  131. package/lib/util/periods.js +98 -64
  132. package/lib/util/player_configuration.js +31 -1
  133. package/lib/util/stream_utils.js +140 -85
  134. package/lib/util/xml_utils.js +31 -12
  135. package/package.json +1 -1
  136. package/roadmap.md +24 -22
  137. package/shaka-player.uncompiled.js +4 -0
  138. package/test/cast/cast_utils_unit.js +1 -0
  139. package/test/cea/cea608_memory_unit.js +1 -1
  140. package/test/cea/cea708_service_unit.js +8 -8
  141. package/test/cea/cea708_window_unit.js +6 -6
  142. package/test/cea/cea_decoder_unit.js +1 -1
  143. package/test/cea/dtvcc_packet_builder_unit.js +2 -2
  144. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  145. package/test/dash/dash_parser_live_unit.js +101 -1
  146. package/test/dash/dash_parser_manifest_unit.js +78 -2
  147. package/test/dash/dash_parser_segment_base_unit.js +2 -0
  148. package/test/dash/dash_parser_segment_list_unit.js +2 -1
  149. package/test/dash/dash_parser_segment_template_unit.js +2 -1
  150. package/test/hls/hls_live_unit.js +2 -0
  151. package/test/hls/hls_parser_unit.js +252 -0
  152. package/test/media/drm_engine_integration.js +86 -12
  153. package/test/media/drm_engine_unit.js +310 -450
  154. package/test/media/quality_observer_unit.js +139 -0
  155. package/test/media/segment_reference_unit.js +16 -1
  156. package/test/media/streaming_engine_integration.js +2 -1
  157. package/test/media/streaming_engine_unit.js +2 -0
  158. package/test/net/http_plugin_unit.js +20 -15
  159. package/test/offline/manifest_convert_unit.js +2 -0
  160. package/test/offline/storage_integration.js +117 -23
  161. package/test/player_integration.js +151 -0
  162. package/test/player_src_equals_integration.js +52 -0
  163. package/test/player_unit.js +11 -33
  164. package/test/test/assets/chapters.srt +11 -0
  165. package/test/test/assets/chapters.vtt +10 -0
  166. package/test/test/util/cea_utils.js +12 -12
  167. package/test/test/util/dash_parser_util.js +4 -0
  168. package/test/test/util/fake_ad.js +7 -0
  169. package/test/test/util/fake_ad_manager.js +7 -0
  170. package/test/test/util/fake_drm_engine.js +9 -2
  171. package/test/test/util/manifest_generator.js +5 -2
  172. package/test/test/util/manifest_parser_util.js +3 -1
  173. package/test/test/util/test_scheme.js +14 -1
  174. package/test/text/ttml_text_parser_unit.js +47 -0
  175. package/test/text/web_vtt_generator_unit.js +81 -7
  176. package/test/ui/ui_unit.js +250 -0
  177. package/test/util/cmcd_manager_unit.js +277 -0
  178. package/test/util/stream_utils_unit.js +118 -10
  179. package/ui/airplay_button.js +2 -1
  180. package/ui/audio_language_selection.js +9 -5
  181. package/ui/cast_button.js +5 -6
  182. package/ui/constants.js +0 -3
  183. package/ui/context_menu.js +109 -0
  184. package/ui/controls.js +41 -7
  185. package/ui/controls.less +1 -0
  186. package/ui/enums.js +4 -0
  187. package/ui/externs/ui.js +28 -1
  188. package/ui/fast_forward_button.js +16 -8
  189. package/ui/fullscreen_button.js +2 -3
  190. package/ui/language_utils.js +1 -1
  191. package/ui/less/buttons.less +0 -4
  192. package/ui/less/containers.less +74 -0
  193. package/ui/less/overflow_menu.less +0 -10
  194. package/ui/less/tooltip.less +97 -0
  195. package/ui/locales/en.json +1 -0
  196. package/ui/locales/source.json +4 -0
  197. package/ui/loop_button.js +6 -3
  198. package/ui/mute_button.js +3 -4
  199. package/ui/overflow_menu.js +7 -28
  200. package/ui/pip_button.js +10 -7
  201. package/ui/play_button.js +2 -2
  202. package/ui/playback_rate_selection.js +11 -15
  203. package/ui/presentation_time.js +1 -3
  204. package/ui/resolution_selection.js +11 -7
  205. package/ui/rewind_button.js +17 -9
  206. package/ui/seek_bar.js +6 -6
  207. package/ui/settings_menu.js +36 -4
  208. package/ui/small_play_button.js +1 -0
  209. package/ui/spacer.js +1 -1
  210. package/ui/statistics_button.js +253 -0
  211. package/ui/text_selection.js +19 -15
  212. package/ui/ui.js +30 -0
  213. package/ui/ui_utils.js +1 -1
  214. package/ui/volume_bar.js +2 -4
@@ -24,10 +24,12 @@ shaka.net.HttpXHRPlugin = class {
24
24
  * @param {shaka.net.NetworkingEngine.RequestType} requestType
25
25
  * @param {shaka.extern.ProgressUpdated} progressUpdated Called when a
26
26
  * progress event happened.
27
+ * @param {shaka.extern.HeadersReceived} headersReceived Called when the
28
+ * headers for the download are received, but before the body is.
27
29
  * @return {!shaka.extern.IAbortableOperation.<shaka.extern.Response>}
28
30
  * @export
29
31
  */
30
- static parse(uri, request, requestType, progressUpdated) {
32
+ static parse(uri, request, requestType, progressUpdated, headersReceived) {
31
33
  const xhr = new shaka.net.HttpXHRPlugin.Xhr_();
32
34
 
33
35
  // Last time stamp when we got a progress event.
@@ -48,23 +50,25 @@ shaka.net.HttpXHRPlugin = class {
48
50
  shaka.util.Error.Code.OPERATION_ABORTED,
49
51
  uri, requestType));
50
52
  };
51
- xhr.onload = (event) => {
52
- const target = event.target;
53
- goog.asserts.assert(target, 'XHR onload has no target!');
54
- // Since Edge incorrectly return the header with a leading new
55
- // line character ('\n'), we trim the header here.
56
- const headerLines = target.getAllResponseHeaders().trim().split('\r\n');
57
- const headers = {};
58
- for (const header of headerLines) {
59
- /** @type {!Array.<string>} */
60
- const parts = header.split(': ');
61
- headers[parts[0].toLowerCase()] = parts.slice(1).join(': ');
53
+ let calledHeadersReceived = false;
54
+ xhr.onreadystatechange = (event) => {
55
+ // See if the readyState is 2 ("HEADERS_RECEIVED").
56
+ if (xhr.readyState == 2 && !calledHeadersReceived) {
57
+ const headers = shaka.net.HttpXHRPlugin.headersToGenericObject_(xhr);
58
+ headersReceived(headers);
59
+ // Don't send out this event twice.
60
+ calledHeadersReceived = true;
62
61
  }
62
+ };
63
+ xhr.onload = (event) => {
64
+ const headers = shaka.net.HttpXHRPlugin.headersToGenericObject_(xhr);
65
+ goog.asserts.assert(xhr.response instanceof ArrayBuffer,
66
+ 'XHR should have a response by now!');
67
+ const xhrResponse = xhr.response;
63
68
 
64
69
  try {
65
70
  const response = shaka.net.HttpPluginUtils.makeResponse(headers,
66
- target.response, target.status, uri, target.responseURL,
67
- requestType);
71
+ xhrResponse, xhr.status, uri, xhr.responseURL, requestType);
68
72
  resolve(response);
69
73
  } catch (error) {
70
74
  goog.asserts.assert(error instanceof shaka.util.Error,
@@ -116,6 +120,24 @@ shaka.net.HttpXHRPlugin = class {
116
120
  return Promise.resolve();
117
121
  });
118
122
  }
123
+
124
+ /**
125
+ * @param {!XMLHttpRequest} xhr
126
+ * @return {!Object.<string, string>}
127
+ * @private
128
+ */
129
+ static headersToGenericObject_(xhr) {
130
+ // Since Edge incorrectly return the header with a leading new
131
+ // line character ('\n'), we trim the header here.
132
+ const headerLines = xhr.getAllResponseHeaders().trim().split('\r\n');
133
+ const headers = {};
134
+ for (const header of headerLines) {
135
+ /** @type {!Array.<string>} */
136
+ const parts = header.split(': ');
137
+ headers[parts[0].toLowerCase()] = parts.slice(1).join(': ');
138
+ }
139
+ return headers;
140
+ }
119
141
  };
120
142
 
121
143
 
@@ -136,4 +158,8 @@ shaka.net.NetworkingEngine.registerScheme(
136
158
  'https', shaka.net.HttpXHRPlugin.parse,
137
159
  shaka.net.NetworkingEngine.PluginPriority.FALLBACK,
138
160
  /* progressSupport= */ true);
161
+ shaka.net.NetworkingEngine.registerScheme(
162
+ 'blob', shaka.net.HttpXHRPlugin.parse,
163
+ shaka.net.NetworkingEngine.PluginPriority.FALLBACK,
164
+ /* progressSupport= */ true);
139
165
 
@@ -48,8 +48,12 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
48
48
  * @param {function(number, number)=} onProgressUpdated Called when a progress
49
49
  * event is triggered. Passed the duration, in milliseconds, that the
50
50
  * request took, and the number of bytes transferred.
51
+ * @param {shaka.net.NetworkingEngine.OnHeadersReceived=} onHeadersReceived
52
+ * Called when the headers are received for a download.
53
+ * @param {shaka.net.NetworkingEngine.OnDownloadFailed=} onDownloadFailed
54
+ * Called when a download fails, for any reason.
51
55
  */
52
- constructor(onProgressUpdated) {
56
+ constructor(onProgressUpdated, onHeadersReceived, onDownloadFailed) {
53
57
  super();
54
58
 
55
59
  /** @private {boolean} */
@@ -67,6 +71,12 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
67
71
  /** @private {?function(number, number)} */
68
72
  this.onProgressUpdated_ = onProgressUpdated || null;
69
73
 
74
+ /** @private {?shaka.net.NetworkingEngine.OnHeadersReceived} */
75
+ this.onHeadersReceived_ = onHeadersReceived || null;
76
+
77
+ /** @private {?shaka.net.NetworkingEngine.OnDownloadFailed} */
78
+ this.onDownloadFailed_ = onDownloadFailed || null;
79
+
70
80
  /** @private {boolean} */
71
81
  this.forceHTTPS_ = false;
72
82
  }
@@ -447,6 +457,8 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
447
457
 
448
458
  let aborted = false;
449
459
 
460
+ let headersReceivedCalled = false;
461
+
450
462
  let startTimeMs;
451
463
  const sendOperation = backoffOperation.chain(() => {
452
464
  if (this.destroyed_) {
@@ -456,23 +468,27 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
456
468
  startTimeMs = Date.now();
457
469
  const segment = shaka.net.NetworkingEngine.RequestType.SEGMENT;
458
470
 
459
- const requestPlugin = plugin(request.uris[index],
460
- request,
461
- type,
462
- // The following function is passed to plugin.
463
- (time, bytes, numBytesRemaining) => {
464
- if (connectionTimer) {
465
- connectionTimer.stop();
466
- }
467
- if (stallTimer) {
468
- stallTimer.tickAfter(stallTimeoutMs / 1000);
469
- }
470
- if (this.onProgressUpdated_ && type == segment) {
471
- this.onProgressUpdated_(time, bytes);
472
- gotProgress = true;
473
- numBytesRemainingObj.setBytes(numBytesRemaining);
474
- }
475
- });
471
+ const progressUpdated = (time, bytes, numBytesRemaining) => {
472
+ if (connectionTimer) {
473
+ connectionTimer.stop();
474
+ }
475
+ if (stallTimer) {
476
+ stallTimer.tickAfter(stallTimeoutMs / 1000);
477
+ }
478
+ if (this.onProgressUpdated_ && type == segment) {
479
+ this.onProgressUpdated_(time, bytes);
480
+ gotProgress = true;
481
+ numBytesRemainingObj.setBytes(numBytesRemaining);
482
+ }
483
+ };
484
+ const headersReceived = (headers) => {
485
+ if (this.onHeadersReceived_) {
486
+ this.onHeadersReceived_(headers, request, type);
487
+ }
488
+ headersReceivedCalled = true;
489
+ };
490
+ const requestPlugin = plugin(
491
+ request.uris[index], request, type, progressUpdated, headersReceived);
476
492
 
477
493
  if (!progressSupport) {
478
494
  return requestPlugin;
@@ -511,6 +527,13 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
511
527
  response: response,
512
528
  gotProgress: gotProgress,
513
529
  };
530
+ if (!headersReceivedCalled) {
531
+ // The plugin did not call headersReceived, perhaps because it is not
532
+ // able to track that information. So, fire the event manually.
533
+ if (this.onHeadersReceived_) {
534
+ this.onHeadersReceived_(response.headers, request, type);
535
+ }
536
+ }
514
537
 
515
538
  return responseAndGotProgress;
516
539
  }, (error) => {
@@ -520,6 +543,17 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
520
543
  if (stallTimer) {
521
544
  stallTimer.stop();
522
545
  }
546
+ if (this.onDownloadFailed_) {
547
+ let shakaError = null;
548
+ let httpResponseCode = 0;
549
+ if (error instanceof shaka.util.Error) {
550
+ shakaError = error;
551
+ if (error.code == shaka.util.Error.Code.BAD_HTTP_STATUS) {
552
+ httpResponseCode = /** @type {number} */ (error.data[1]);
553
+ }
554
+ }
555
+ this.onDownloadFailed_(request, shakaError, httpResponseCode, aborted);
556
+ }
523
557
  if (this.destroyed_) {
524
558
  return shaka.util.AbortableOperation.aborted();
525
559
  }
@@ -707,6 +741,7 @@ shaka.net.NetworkingEngine.RequestType = {
707
741
  'LICENSE': 2,
708
742
  'APP': 3,
709
743
  'TIMING': 4,
744
+ 'SERVER_CERTIFICATE': 5,
710
745
  };
711
746
 
712
747
 
@@ -763,3 +798,32 @@ shaka.net.NetworkingEngine.schemes_ = {};
763
798
  * @private
764
799
  */
765
800
  shaka.net.NetworkingEngine.ResponseAndGotProgress;
801
+
802
+
803
+ /**
804
+ * @typedef {function(
805
+ * !Object.<string, string>,
806
+ * !shaka.extern.Request,
807
+ * !shaka.net.NetworkingEngine.RequestType)}
808
+ *
809
+ * @description
810
+ * A callback function that passes the shaka.extern.HeadersReceived along to
811
+ * the player, plus some extra data.
812
+ * @export
813
+ */
814
+ shaka.net.NetworkingEngine.OnHeadersReceived;
815
+
816
+
817
+ /**
818
+ * @typedef {function(
819
+ * !shaka.extern.Request,
820
+ * ?shaka.util.Error,
821
+ * number,
822
+ * boolean)}
823
+ *
824
+ * @description
825
+ * A callback function that notifies the player when a download fails, for any
826
+ * reason (e.g. even if the download was aborted).
827
+ * @export
828
+ */
829
+ shaka.net.NetworkingEngine.OnDownloadFailed;
@@ -0,0 +1,68 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ goog.provide('shaka.offline.DownloadInfo');
8
+
9
+ goog.require('shaka.util.Networking');
10
+ goog.requireType('shaka.media.InitSegmentReference');
11
+ goog.requireType('shaka.media.SegmentReference');
12
+
13
+
14
+ /**
15
+ * An object that represents a single segment, that the storage system will soon
16
+ * download, but has not yet started downloading.
17
+ */
18
+ shaka.offline.DownloadInfo = class {
19
+ /**
20
+ * @param {shaka.media.SegmentReference|shaka.media.InitSegmentReference} ref
21
+ * @param {number} estimateId
22
+ * @param {number} groupId
23
+ * @param {boolean} isInitSegment
24
+ */
25
+ constructor(ref, estimateId, groupId, isInitSegment) {
26
+ /** @type {shaka.media.SegmentReference|shaka.media.InitSegmentReference} */
27
+ this.ref = ref;
28
+
29
+ /** @type {number} */
30
+ this.estimateId = estimateId;
31
+
32
+ /** @type {number} */
33
+ this.groupId = groupId;
34
+
35
+ /** @type {boolean} */
36
+ this.isInitSegment = isInitSegment;
37
+ }
38
+
39
+ /**
40
+ * Creates an ID that encapsulates all important information in the ref, which
41
+ * can then be used to check for equality.
42
+ * @param {shaka.media.SegmentReference|shaka.media.InitSegmentReference} ref
43
+ * @return {string}
44
+ */
45
+ static idForSegmentRef(ref) {
46
+ // Escape the URIs using encodeURI, to make sure that a weirdly formed URI
47
+ // cannot cause two unrelated refs to be considered equivalent.
48
+ return ref.getUris().map((uri) => '{' + encodeURI(uri) + '}').join('') +
49
+ ':' + ref.startByte + ':' + ref.endByte;
50
+ }
51
+
52
+ /** @return {string} */
53
+ getRefId() {
54
+ return shaka.offline.DownloadInfo.idForSegmentRef(this.ref);
55
+ }
56
+
57
+ /**
58
+ * @param {shaka.extern.PlayerConfiguration} config
59
+ * @return {!shaka.extern.Request}
60
+ */
61
+ makeSegmentRequest(config) {
62
+ return shaka.util.Networking.createSegmentRequest(
63
+ this.ref.getUris(),
64
+ this.ref.startByte,
65
+ this.ref.endByte,
66
+ config.streaming.retryParameters);
67
+ }
68
+ };
@@ -44,9 +44,8 @@ shaka.offline.DownloadManager = class {
44
44
 
45
45
  /** @private {!shaka.util.Destroyer} */
46
46
  this.destroyer_ = new shaka.util.Destroyer(() => {
47
- const promises = Array.from(this.groups_.values());
48
47
  // Add a "catch" block to stop errors from being returned.
49
- return Promise.all(promises.map((p) => p.catch(() => {})));
48
+ return this.abortAll().catch(() => {});
50
49
  });
51
50
 
52
51
  /**
@@ -103,6 +102,16 @@ shaka.offline.DownloadManager = class {
103
102
  return Promise.all(promises);
104
103
  }
105
104
 
105
+ /**
106
+ * Adds a byte length to the download estimate.
107
+ *
108
+ * @param {number} estimatedByteLength
109
+ * @return {number} estimateId
110
+ */
111
+ addDownloadEstimate(estimatedByteLength) {
112
+ return this.estimator_.open(estimatedByteLength);
113
+ }
114
+
106
115
  /**
107
116
  * Add a request to be downloaded as part of a group.
108
117
  *
@@ -110,18 +119,16 @@ shaka.offline.DownloadManager = class {
110
119
  * The group to add this segment to. If the group does not exist, a new
111
120
  * group will be created.
112
121
  * @param {shaka.extern.Request} request
113
- * @param {number} estimatedByteLength
122
+ * @param {number} estimateId
114
123
  * @param {boolean} isInitSegment
115
124
  * @param {function(BufferSource):!Promise} onDownloaded
116
125
  * The callback for when this request has been downloaded. Downloading for
117
126
  * |group| will pause until the promise returned by |onDownloaded| resolves.
118
127
  * @return {!Promise} Resolved when this request is complete.
119
128
  */
120
- queue(groupId, request, estimatedByteLength, isInitSegment, onDownloaded) {
129
+ queue(groupId, request, estimateId, isInitSegment, onDownloaded) {
121
130
  this.destroyer_.ensureNotDestroyed();
122
131
 
123
- const id = this.estimator_.open(estimatedByteLength);
124
-
125
132
  const group = this.groups_.get(groupId) || Promise.resolve();
126
133
 
127
134
  // Add another download to the group.
@@ -149,7 +156,7 @@ shaka.offline.DownloadManager = class {
149
156
  }
150
157
 
151
158
  // Update all our internal stats.
152
- this.estimator_.close(id, response.byteLength);
159
+ this.estimator_.close(estimateId, response.byteLength);
153
160
  this.onProgress_(
154
161
  this.estimator_.getEstimatedProgress(),
155
162
  this.estimator_.getTotalDownloaded());
@@ -68,6 +68,28 @@ shaka.offline.indexeddb.BaseStorageCell = class {
68
68
  return this.rejectAdd(this.manifestStore_);
69
69
  }
70
70
 
71
+ /** @override */
72
+ updateManifest(key, manifest) {
73
+ // By default, reject all updates.
74
+ return this.rejectUpdate(this.manifestStore_);
75
+ }
76
+
77
+ /**
78
+ * @param {number} key
79
+ * @param {!shaka.extern.ManifestDB} manifest
80
+ * @return {!Promise}
81
+ * @protected
82
+ */
83
+ updateManifestImplementation(key, manifest) {
84
+ const op = this.connection_.startReadWriteOperation(this.manifestStore_);
85
+ const store = op.store();
86
+ store.get(key).onsuccess = (e) => {
87
+ store.put(manifest, key);
88
+ };
89
+
90
+ return op.promise();
91
+ }
92
+
71
93
  /** @override */
72
94
  updateManifestExpiration(key, newExpiration) {
73
95
  const op = this.connection_.startReadWriteOperation(this.manifestStore_);
@@ -145,6 +167,19 @@ shaka.offline.indexeddb.BaseStorageCell = class {
145
167
  'Cannot add new value to ' + storeName));
146
168
  }
147
169
 
170
+ /**
171
+ * @param {string} storeName
172
+ * @return {!Promise}
173
+ * @protected
174
+ */
175
+ rejectUpdate(storeName) {
176
+ return Promise.reject(new shaka.util.Error(
177
+ shaka.util.Error.Severity.CRITICAL,
178
+ shaka.util.Error.Category.STORAGE,
179
+ shaka.util.Error.Code.MODIFY_OPERATION_NOT_SUPPORTED,
180
+ 'Cannot modify values in ' + storeName));
181
+ }
182
+
148
183
  /**
149
184
  * @param {string} storeName
150
185
  * @param {!Array.<T>} values
@@ -315,7 +315,7 @@ shaka.offline.indexeddb.StorageMechanism = class {
315
315
 
316
316
  const del = window.indexedDB.deleteDatabase(name);
317
317
  del.onblocked = (event) => {
318
- shaka.log.warning('Deleting', name, 'is being blocked');
318
+ shaka.log.warning('Deleting', name, 'is being blocked', event);
319
319
  };
320
320
  del.onsuccess = (event) => {
321
321
  p.resolve();
@@ -204,6 +204,7 @@ shaka.offline.indexeddb.V1StorageCell = class
204
204
  appendWindowStart,
205
205
  appendWindowEnd,
206
206
  timestampOffset,
207
+ tilesLayout: '',
207
208
  };
208
209
  }
209
210
 
@@ -148,6 +148,7 @@ shaka.offline.indexeddb.V2StorageCell = class
148
148
  appendWindowEnd: periodEnd,
149
149
  timestampOffset,
150
150
  dataKey: old.dataKey,
151
+ tilesLayout: '',
151
152
  };
152
153
  }
153
154
  };
@@ -33,6 +33,11 @@ shaka.offline.indexeddb.V5StorageCell = class
33
33
  return this.add(this.manifestStore_, manifests);
34
34
  }
35
35
 
36
+ /** @override */
37
+ updateManifest(key, manifest) {
38
+ return this.updateManifestImplementation(key, manifest);
39
+ }
40
+
36
41
  /** @override */
37
42
  convertManifest(old) {
38
43
  // JSON serialization turns Infinity into null, so turn it back now.
@@ -229,7 +229,9 @@ shaka.offline.ManifestConverter = class {
229
229
  initSegmentReference,
230
230
  segmentDB.timestampOffset,
231
231
  segmentDB.appendWindowStart,
232
- segmentDB.appendWindowEnd);
232
+ segmentDB.appendWindowEnd,
233
+ /* partialReferences= */ [],
234
+ segmentDB.tilesLayout || '');
233
235
  }
234
236
 
235
237
  /**