shaka-player 3.2.1 → 3.3.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 (213) 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 +9 -5
  5. package/CHANGELOG.md +358 -0
  6. package/CONTRIBUTORS +7 -2
  7. package/build/conformance.textproto +183 -169
  8. package/build/generateExterns.js +1 -1
  9. package/build/types/core +3 -0
  10. package/build/types/offline +1 -0
  11. package/build/types/polyfill +1 -0
  12. package/build/types/ui +2 -0
  13. package/demo/common/assets.js +19 -1
  14. package/demo/common/message_ids.js +13 -1
  15. package/demo/config.js +31 -1
  16. package/demo/index.html +1 -1
  17. package/demo/locales/en.json +12 -0
  18. package/demo/locales/source.json +48 -0
  19. package/dist/controls.css +26 -2
  20. package/dist/controls.css.map +1 -1
  21. package/dist/demo.compiled.debug.js +20 -17
  22. package/dist/demo.compiled.debug.map +3 -3
  23. package/dist/demo.compiled.js +20 -17
  24. package/dist/demo.compiled.map +3 -3
  25. package/dist/deps.js +19 -12
  26. package/dist/locales.js +39 -37
  27. package/dist/receiver.compiled.debug.js +12 -10
  28. package/dist/receiver.compiled.debug.map +3 -3
  29. package/dist/receiver.compiled.js +12 -10
  30. package/dist/receiver.compiled.map +3 -3
  31. package/dist/shaka-player.compiled.d.ts +231 -18
  32. package/dist/shaka-player.compiled.debug.d.ts +231 -18
  33. package/dist/shaka-player.compiled.debug.externs.js +279 -8
  34. package/dist/shaka-player.compiled.debug.js +512 -449
  35. package/dist/shaka-player.compiled.debug.map +4 -4
  36. package/dist/shaka-player.compiled.externs.js +279 -8
  37. package/dist/shaka-player.compiled.js +854 -821
  38. package/dist/shaka-player.compiled.map +4 -4
  39. package/dist/shaka-player.ui.d.ts +247 -19
  40. package/dist/shaka-player.ui.debug.d.ts +247 -19
  41. package/dist/shaka-player.ui.debug.externs.js +307 -9
  42. package/dist/shaka-player.ui.debug.js +662 -580
  43. package/dist/shaka-player.ui.debug.map +4 -4
  44. package/dist/shaka-player.ui.externs.js +307 -9
  45. package/dist/shaka-player.ui.js +1047 -1000
  46. package/dist/shaka-player.ui.map +4 -4
  47. package/docs/design/bg-fetch-after.gv +29 -0
  48. package/docs/design/bg-fetch-after.gv.png +0 -0
  49. package/docs/design/bg-fetch-before.gv +18 -0
  50. package/docs/design/bg-fetch-before.gv.png +0 -0
  51. package/docs/design/bg-fetch.md +134 -0
  52. package/docs/tutorials/blob-url.md +15 -0
  53. package/docs/tutorials/fairplay.md +1 -1
  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/cmcd.js +186 -0
  58. package/externs/ima.js +3 -0
  59. package/externs/shaka/ads.js +5 -0
  60. package/externs/shaka/manifest.js +12 -1
  61. package/externs/shaka/manifest_parser.js +10 -1
  62. package/externs/shaka/net.js +20 -4
  63. package/externs/shaka/offline.js +31 -2
  64. package/externs/shaka/player.js +138 -5
  65. package/externs/shaka/text.js +24 -0
  66. package/externs/webcrypto.js +18 -0
  67. package/karma.conf.js +1 -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/client_side_ad.js +8 -0
  72. package/lib/ads/client_side_ad_manager.js +54 -90
  73. package/lib/ads/server_side_ad.js +7 -0
  74. package/lib/ads/server_side_ad_manager.js +7 -10
  75. package/lib/cast/cast_proxy.js +3 -2
  76. package/lib/cast/cast_receiver.js +2 -1
  77. package/lib/cast/cast_sender.js +2 -2
  78. package/lib/cast/cast_utils.js +1 -0
  79. package/lib/dash/dash_parser.js +141 -16
  80. package/lib/dash/segment_base.js +25 -1
  81. package/lib/dash/segment_list.js +19 -10
  82. package/lib/dash/segment_template.js +24 -11
  83. package/lib/hls/hls_parser.js +146 -40
  84. package/lib/media/drm_engine.js +7 -0
  85. package/lib/media/gap_jumping_controller.js +4 -2
  86. package/lib/media/media_source_engine.js +1 -2
  87. package/lib/media/quality_observer.js +291 -0
  88. package/lib/media/segment_index.js +8 -1
  89. package/lib/media/segment_reference.js +37 -4
  90. package/lib/media/streaming_engine.js +49 -7
  91. package/lib/net/http_fetch_plugin.js +31 -11
  92. package/lib/net/http_plugin_utils.js +1 -0
  93. package/lib/net/http_xhr_plugin.js +40 -14
  94. package/lib/net/networking_engine.js +83 -19
  95. package/lib/offline/download_info.js +68 -0
  96. package/lib/offline/download_manager.js +13 -5
  97. package/lib/offline/indexeddb/base_storage_cell.js +35 -0
  98. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  99. package/lib/offline/indexeddb/v5_storage_cell.js +5 -0
  100. package/lib/offline/storage.js +393 -284
  101. package/lib/offline/stored_content_utils.js +2 -0
  102. package/lib/player.js +249 -43
  103. package/lib/polyfill/media_capabilities.js +36 -15
  104. package/lib/polyfill/mediasource.js +6 -0
  105. package/lib/polyfill/orientation.js +1 -1
  106. package/lib/polyfill/patchedmediakeys_apple.js +4 -4
  107. package/lib/polyfill/patchedmediakeys_ms.js +4 -4
  108. package/lib/polyfill/patchedmediakeys_webkit.js +4 -4
  109. package/lib/polyfill/random_uuid.js +52 -0
  110. package/lib/text/cue.js +18 -0
  111. package/lib/text/mp4_ttml_parser.js +3 -0
  112. package/lib/text/text_engine.js +14 -2
  113. package/lib/text/ttml_text_parser.js +114 -60
  114. package/lib/text/ui_text_displayer.js +95 -41
  115. package/lib/util/cmcd_manager.js +672 -0
  116. package/lib/util/error.js +6 -0
  117. package/lib/util/fake_event.js +53 -7
  118. package/lib/util/language_utils.js +12 -0
  119. package/lib/util/mutex.js +52 -0
  120. package/lib/util/periods.js +102 -65
  121. package/lib/util/platform.js +13 -1
  122. package/lib/util/player_configuration.js +18 -0
  123. package/lib/util/stream_utils.js +99 -10
  124. package/lib/util/xml_utils.js +19 -0
  125. package/package.json +2 -2
  126. package/shaka-player.uncompiled.js +3 -0
  127. package/test/cast/cast_proxy_unit.js +12 -6
  128. package/test/cast/cast_utils_unit.js +1 -1
  129. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  130. package/test/dash/dash_parser_live_unit.js +101 -1
  131. package/test/dash/dash_parser_manifest_unit.js +222 -2
  132. package/test/dash/dash_parser_segment_base_unit.js +2 -0
  133. package/test/dash/dash_parser_segment_list_unit.js +2 -1
  134. package/test/dash/dash_parser_segment_template_unit.js +2 -1
  135. package/test/hls/hls_live_unit.js +2 -0
  136. package/test/hls/hls_parser_unit.js +7 -1
  137. package/test/media/closed_caption_parser_unit.js +6 -1
  138. package/test/media/drm_engine_unit.js +47 -3
  139. package/test/media/quality_observer_unit.js +139 -0
  140. package/test/media/segment_reference_unit.js +16 -1
  141. package/test/media/streaming_engine_integration.js +4 -2
  142. package/test/media/streaming_engine_unit.js +147 -0
  143. package/test/net/http_plugin_unit.js +20 -15
  144. package/test/offline/storage_integration.js +108 -4
  145. package/test/player_integration.js +178 -8
  146. package/test/player_src_equals_integration.js +41 -8
  147. package/test/player_unit.js +19 -9
  148. package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
  149. package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
  150. package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
  151. package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
  152. package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
  153. package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
  154. package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
  155. package/test/test/assets/3675/dash_0.mpd +30 -0
  156. package/test/test/assets/3675/dash_1.mpd +30 -0
  157. package/test/test/assets/3675/dash_2.mpd +30 -0
  158. package/test/test/assets/3675/dash_3.mpd +30 -0
  159. package/test/test/assets/3675/dash_4.mpd +30 -0
  160. package/test/test/assets/3675/dash_5.mpd +26 -0
  161. package/test/test/assets/3675/init-stream0.m4s +0 -0
  162. package/test/test/assets/chapters.vtt +2 -2
  163. package/test/test/assets/chapters2.vtt +10 -0
  164. package/test/test/util/dash_parser_util.js +4 -0
  165. package/test/test/util/fake_ad.js +7 -0
  166. package/test/test/util/fake_ad_manager.js +1 -1
  167. package/test/test/util/fake_drm_engine.js +9 -2
  168. package/test/test/util/manifest_generator.js +3 -2
  169. package/test/test/util/test_scheme.js +14 -1
  170. package/test/test/util/ttml_utils.js +81 -0
  171. package/test/text/mp4_ttml_parser_unit.js +11 -18
  172. package/test/text/ttml_text_parser_unit.js +552 -227
  173. package/test/text/ui_text_displayer_unit.js +29 -17
  174. package/test/ui/localization_unit.js +15 -14
  175. package/test/ui/text_displayer_layout_unit.js +13 -1
  176. package/test/ui/ui_unit.js +250 -0
  177. package/test/util/cmcd_manager_unit.js +291 -0
  178. package/test/util/stream_utils_unit.js +45 -4
  179. package/third_party/closure-uri/uri.js +21 -0
  180. package/ui/airplay_button.js +1 -0
  181. package/ui/audio_language_selection.js +7 -0
  182. package/ui/cast_button.js +3 -3
  183. package/ui/context_menu.js +109 -0
  184. package/ui/controls.js +45 -13
  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 +14 -5
  189. package/ui/fullscreen_button.js +1 -0
  190. package/ui/less/buttons.less +0 -4
  191. package/ui/less/containers.less +77 -7
  192. package/ui/less/overflow_menu.less +0 -10
  193. package/ui/less/tooltip.less +97 -0
  194. package/ui/locales/en.json +1 -0
  195. package/ui/locales/ru.json +6 -6
  196. package/ui/locales/source.json +4 -0
  197. package/ui/localization.js +28 -51
  198. package/ui/loop_button.js +5 -0
  199. package/ui/mute_button.js +2 -1
  200. package/ui/overflow_menu.js +5 -25
  201. package/ui/pip_button.js +7 -3
  202. package/ui/play_button.js +2 -2
  203. package/ui/playback_rate_selection.js +8 -9
  204. package/ui/resolution_selection.js +7 -0
  205. package/ui/rewind_button.js +15 -6
  206. package/ui/seek_bar.js +4 -2
  207. package/ui/settings_menu.js +36 -4
  208. package/ui/small_play_button.js +1 -0
  209. package/ui/statistics_button.js +253 -0
  210. package/ui/text_selection.js +12 -4
  211. package/ui/ui.js +30 -0
  212. package/ui/volume_bar.js +1 -1
  213. package/externs/media_capabilities.js +0 -16
@@ -6,6 +6,8 @@
6
6
 
7
7
  goog.provide('shaka.util.FakeEvent');
8
8
 
9
+ goog.require('goog.asserts');
10
+
9
11
 
10
12
  /**
11
13
  * @summary Create an Event work-alike object based on the provided dictionary.
@@ -16,18 +18,62 @@ goog.provide('shaka.util.FakeEvent');
16
18
  */
17
19
  shaka.util.FakeEvent = class {
18
20
  /**
19
- * @param {string} type
20
- * @param {Object=} dict
21
+ * @param {!Event} event
22
+ * @return {!shaka.util.FakeEvent}
21
23
  */
22
- constructor(type, dict = {}) {
23
- // Take properties from dict if present.
24
- for (const key in dict) {
25
- Object.defineProperty(this, key, {
26
- value: dict[key],
24
+ static fromRealEvent(event) {
25
+ const fakeEvent = new shaka.util.FakeEvent(event.type);
26
+ for (const key in event) {
27
+ Object.defineProperty(fakeEvent, key, {
28
+ value: event[key],
27
29
  writable: true,
28
30
  enumerable: true,
29
31
  });
30
32
  }
33
+ return fakeEvent;
34
+ }
35
+
36
+ /**
37
+ * Allows us to tell the compiler that the dictionary "map" is actually a
38
+ * generic object, for backwards compatibility.
39
+ * @param {!Map.<string, Object>} dict
40
+ * @return {!Object}
41
+ * @suppress {invalidCasts}
42
+ * @private
43
+ */
44
+ static recastDictAsObject_(dict) {
45
+ goog.asserts.assert(!(dict instanceof Map), 'dict should not be a map');
46
+ return /** @type {!Object} */ (dict);
47
+ }
48
+
49
+ /**
50
+ * @param {string} type
51
+ * @param {Map.<string, Object>=} dict
52
+ */
53
+ constructor(type, dict) {
54
+ if (dict) {
55
+ if (dict instanceof Map) {
56
+ // Take properties from dict if present.
57
+ for (const key of dict.keys()) {
58
+ Object.defineProperty(this, key, {
59
+ value: dict.get(key),
60
+ writable: true,
61
+ enumerable: true,
62
+ });
63
+ }
64
+ } else {
65
+ // For backwards compatibility with external apps that may make use of
66
+ // this public constructor, this should still accept generic objects.
67
+ const obj = shaka.util.FakeEvent.recastDictAsObject_(dict);
68
+ for (const key in obj) {
69
+ Object.defineProperty(this, key, {
70
+ value: obj[key],
71
+ writable: true,
72
+ enumerable: true,
73
+ });
74
+ }
75
+ }
76
+ }
31
77
 
32
78
  // The properties below cannot be set by the dict. They are all provided
33
79
  // for compatibility with native events.
@@ -13,6 +13,7 @@ goog.require('shaka.util.ManifestParserUtils');
13
13
  /**
14
14
  * @summary A set of language utility functions.
15
15
  * @final
16
+ * @export
16
17
  */
17
18
  shaka.util.LanguageUtils = class {
18
19
  /**
@@ -32,6 +33,7 @@ shaka.util.LanguageUtils = class {
32
33
  * @param {string} locale1
33
34
  * @param {string} locale2
34
35
  * @return {boolean}
36
+ * @export
35
37
  */
36
38
  static areLocaleCompatible(locale1, locale2) {
37
39
  const LanguageUtils = shaka.util.LanguageUtils;
@@ -62,6 +64,7 @@ shaka.util.LanguageUtils = class {
62
64
  * @param {string} locale1
63
65
  * @param {string} locale2
64
66
  * @return {boolean}
67
+ * @export
65
68
  */
66
69
  static areLanguageCompatible(locale1, locale2) {
67
70
  const LanguageUtils = shaka.util.LanguageUtils;
@@ -102,6 +105,7 @@ shaka.util.LanguageUtils = class {
102
105
  * @param {string} possibleParent
103
106
  * @param {string} possibleChild
104
107
  * @return {boolean}
108
+ * @export
105
109
  */
106
110
  static isParentOf(possibleParent, possibleChild) {
107
111
  const LanguageUtils = shaka.util.LanguageUtils;
@@ -146,6 +150,7 @@ shaka.util.LanguageUtils = class {
146
150
  * @param {string} localeA
147
151
  * @param {string} localeB
148
152
  * @return {boolean}
153
+ * @export
149
154
  */
150
155
  static isSiblingOf(localeA, localeB) {
151
156
  const LanguageUtils = shaka.util.LanguageUtils;
@@ -181,6 +186,7 @@ shaka.util.LanguageUtils = class {
181
186
  *
182
187
  * @param {string} locale
183
188
  * @return {string}
189
+ * @export
184
190
  */
185
191
  static normalize(locale) {
186
192
  const LanguageUtils = shaka.util.LanguageUtils;
@@ -217,6 +223,7 @@ shaka.util.LanguageUtils = class {
217
223
  * @param {string} a
218
224
  * @param {string} b
219
225
  * @return {boolean}
226
+ * @export
220
227
  */
221
228
  static areSiblings(a, b) {
222
229
  const LanguageUtils = shaka.util.LanguageUtils;
@@ -235,6 +242,7 @@ shaka.util.LanguageUtils = class {
235
242
  * @param {string} target
236
243
  * @param {string} candidate
237
244
  * @return {number}
245
+ * @export
238
246
  */
239
247
  static relatedness(target, candidate) {
240
248
  const LanguageUtils = shaka.util.LanguageUtils;
@@ -271,6 +279,7 @@ shaka.util.LanguageUtils = class {
271
279
  *
272
280
  * @param {string} lang
273
281
  * @return {string}
282
+ * @export
274
283
  */
275
284
  static getBase(lang) {
276
285
  const LanguageUtils = shaka.util.LanguageUtils;
@@ -300,6 +309,7 @@ shaka.util.LanguageUtils = class {
300
309
  *
301
310
  * @param {shaka.extern.Stream} stream
302
311
  * @return {string}
312
+ * @export
303
313
  */
304
314
  static getLocaleForText(stream) {
305
315
  const LanguageUtils = shaka.util.LanguageUtils;
@@ -322,6 +332,7 @@ shaka.util.LanguageUtils = class {
322
332
  *
323
333
  * @param {shaka.extern.Variant} variant
324
334
  * @return {string}
335
+ * @export
325
336
  */
326
337
  static getLocaleForVariant(variant) {
327
338
  const LanguageUtils = shaka.util.LanguageUtils;
@@ -356,6 +367,7 @@ shaka.util.LanguageUtils = class {
356
367
  * @param {string} target
357
368
  * @param {!Iterable.<string>} searchSpace
358
369
  * @return {?string}
370
+ * @export
359
371
  */
360
372
  static findClosestLocale(target, searchSpace) {
361
373
  const LanguageUtils = shaka.util.LanguageUtils;
@@ -0,0 +1,52 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ goog.provide('shaka.util.Mutex');
8
+
9
+
10
+ /**
11
+ * @summary A simple mutex.
12
+ */
13
+ shaka.util.Mutex = class {
14
+ /** Creates the mutex. */
15
+ constructor() {
16
+ /** @private {!Array.<function()>} */
17
+ this.waiting_ = [];
18
+
19
+ /** @private {number} */
20
+ this.nextMutexId_ = 0;
21
+
22
+ /** @private {number} */
23
+ this.acquiredMutexId_ = 0;
24
+ }
25
+
26
+ /** @return {!Promise.<number>} mutexId */
27
+ async acquire() {
28
+ const mutexId = ++this.nextMutexId_;
29
+ if (!this.acquiredMutexId_) {
30
+ this.acquiredMutexId_ = mutexId;
31
+ } else {
32
+ await (new Promise((resolve, reject) => {
33
+ this.waiting_.push(() => {
34
+ this.acquiredMutexId_ = mutexId;
35
+ resolve();
36
+ });
37
+ }));
38
+ }
39
+ return mutexId;
40
+ }
41
+
42
+ /** @param {number} mutexId */
43
+ release(mutexId) {
44
+ if (mutexId == this.acquiredMutexId_) {
45
+ this.acquiredMutexId_ = 0;
46
+ if (this.waiting_.length > 0) {
47
+ const callback = this.waiting_.shift();
48
+ callback();
49
+ }
50
+ }
51
+ }
52
+ };
@@ -80,7 +80,10 @@ shaka.util.PeriodCombiner = class {
80
80
 
81
81
  /** @return {!Array.<shaka.extern.Stream>} */
82
82
  getTextStreams() {
83
- return this.textStreams_;
83
+ // Return a copy of the array because makeTextStreamsForClosedCaptions
84
+ // may make changes to the contents of the array. Those changes should not
85
+ // propagate back to the PeriodCombiner.
86
+ return this.textStreams_.slice();
84
87
  }
85
88
 
86
89
  /** @return {!Array.<shaka.extern.Stream>} */
@@ -544,8 +547,7 @@ shaka.util.PeriodCombiner = class {
544
547
  for (const stream of unusedStreams) {
545
548
  // Create a new output stream which includes this input stream.
546
549
  const outputStream =
547
- // eslint-disable-next-line no-await-in-loop
548
- await shaka.util.PeriodCombiner.createNewOutputStream_(
550
+ shaka.util.PeriodCombiner.createNewOutputStream_(
549
551
  stream, streamsPerPeriod, clone, concat,
550
552
  unusedStreamsPerPeriod);
551
553
  if (outputStream) {
@@ -616,52 +618,69 @@ shaka.util.PeriodCombiner = class {
616
618
  static async extendExistingOutputStream_(
617
619
  outputStream, streamsPerPeriod, firstNewPeriodIndex, concat,
618
620
  unusedStreamsPerPeriod) {
619
- const matches = shaka.util.PeriodCombiner.findMatchesInAllPeriods_(
620
- streamsPerPeriod, outputStream);
621
-
622
- if (!matches) {
623
- // We were unable to extend this output stream.
624
- shaka.log.error('No matches extending output stream!',
625
- outputStream, streamsPerPeriod);
626
- return false;
627
- }
621
+ shaka.util.PeriodCombiner.findMatchesInAllPeriods_(streamsPerPeriod,
622
+ outputStream);
628
623
 
629
624
  // This only exists where T == Stream, and this should only ever be called
630
625
  // on Stream types. StreamDB should not have pre-existing output streams.
631
626
  goog.asserts.assert(outputStream.createSegmentIndex,
632
627
  'outputStream should be a Stream type!');
633
628
 
629
+ if (!outputStream.matchedStreams) {
630
+ // We were unable to extend this output stream.
631
+ shaka.log.error('No matches extending output stream!',
632
+ outputStream, streamsPerPeriod);
633
+ return false;
634
+ }
634
635
  // We need to create all the per-period segment indexes and append them to
635
636
  // the output's MetaSegmentIndex.
636
- await shaka.util.PeriodCombiner.createSegmentIndexes_(matches);
637
-
638
- // Assure the compiler that matches didn't become null during the async
639
- // operation above.
640
- goog.asserts.assert(matches, 'Matches should be non-null');
637
+ if (outputStream.segmentIndex) {
638
+ await shaka.util.PeriodCombiner.extendOutputSegmentIndex_(outputStream,
639
+ firstNewPeriodIndex);
640
+ }
641
641
 
642
- shaka.util.PeriodCombiner.extendOutputStream_(
643
- outputStream, matches, firstNewPeriodIndex, concat,
644
- unusedStreamsPerPeriod);
642
+ shaka.util.PeriodCombiner.extendOutputStream_(outputStream,
643
+ firstNewPeriodIndex, concat, unusedStreamsPerPeriod);
645
644
  return true;
646
645
  }
647
646
 
648
647
  /**
649
- * Creates all segment indexes for an array of streams. Returns once every
650
- * segment index is created.
648
+ * Creates the segment indexes for an array of input streams, and append them
649
+ * to the output stream's segment index.
651
650
  *
652
- * @param {!Array.<!shaka.extern.Stream>} streams
653
- * @return {!Promise}
651
+ * @param {shaka.extern.Stream} outputStream
652
+ * @param {number} firstNewPeriodIndex An index into streamsPerPeriod which
653
+ * represents the first new period that hasn't been processed yet.
654
654
  * @private
655
655
  */
656
- static createSegmentIndexes_(streams) {
656
+ static async extendOutputSegmentIndex_(outputStream, firstNewPeriodIndex) {
657
657
  const operations = [];
658
+ const streams = outputStream.matchedStreams;
659
+ goog.asserts.assert(streams, 'matched streams should be valid');
660
+
658
661
  for (const stream of streams) {
659
662
  operations.push(stream.createSegmentIndex());
660
663
  if (stream.trickModeVideo && !stream.trickModeVideo.segmentIndex) {
661
664
  operations.push(stream.trickModeVideo.createSegmentIndex());
662
665
  }
663
666
  }
664
- return Promise.all(operations);
667
+ await Promise.all(operations);
668
+
669
+ // Concatenate the new matches onto the stream, starting at the first new
670
+ // period.
671
+ const Iterables = shaka.util.Iterables;
672
+ // Satisfy the compiler about the type.
673
+ // Also checks if the segmentIndex is still valid after the async
674
+ // operations, to make sure we stop if the active stream has changed.
675
+ if (outputStream.segmentIndex instanceof shaka.media.MetaSegmentIndex) {
676
+ for (const {i, item: match} of Iterables.enumerate(streams)) {
677
+ if (match.segmentIndex && i >= firstNewPeriodIndex) {
678
+ goog.asserts.assert(match.segmentIndex,
679
+ 'stream should have a segmentIndex.');
680
+ outputStream.segmentIndex.appendSegmentIndex(match.segmentIndex);
681
+ }
682
+ }
683
+ }
665
684
  }
666
685
 
667
686
  /**
@@ -679,7 +698,7 @@ shaka.util.PeriodCombiner = class {
679
698
  * @param {!Array.<!Set.<T>>} unusedStreamsPerPeriod An array of sets of
680
699
  * unused streams from each period.
681
700
  *
682
- * @return {!Promise.<?T>} A newly-created output Stream, or null if matches
701
+ * @return {?T} A newly-created output Stream, or null if matches
683
702
  * could not be found.`
684
703
  *
685
704
  * @template T
@@ -687,35 +706,36 @@ shaka.util.PeriodCombiner = class {
687
706
  *
688
707
  * @private
689
708
  */
690
- static async createNewOutputStream_(
709
+ static createNewOutputStream_(
691
710
  stream, streamsPerPeriod, clone, concat, unusedStreamsPerPeriod) {
692
711
  // Start by cloning the stream without segments, key IDs, etc.
693
712
  const outputStream = clone(stream);
694
713
 
695
714
  // Find best-matching streams in all periods.
696
- const matches = shaka.util.PeriodCombiner.findMatchesInAllPeriods_(
697
- streamsPerPeriod, outputStream);
698
-
699
- if (!matches) {
700
- // This is not a stream we can build output from, but it may become part
701
- // of another output based on another period's stream.
702
- return null;
703
- }
715
+ shaka.util.PeriodCombiner.findMatchesInAllPeriods_(streamsPerPeriod,
716
+ outputStream);
704
717
 
705
718
  // This only exists where T == Stream.
706
719
  if (outputStream.createSegmentIndex) {
720
+ // Override the createSegmentIndex function of the outputStream.
721
+ outputStream.createSegmentIndex = async () => {
722
+ if (!outputStream.segmentIndex) {
723
+ outputStream.segmentIndex = new shaka.media.MetaSegmentIndex();
724
+ await shaka.util.PeriodCombiner.extendOutputSegmentIndex_(
725
+ outputStream, /* firstNewPeriodIndex= */ 0);
726
+ }
727
+ };
707
728
  // For T == Stream, we need to create all the per-period segment indexes
708
729
  // in advance. concat() will add them to the output's MetaSegmentIndex.
709
- await shaka.util.PeriodCombiner.createSegmentIndexes_(matches);
710
730
  }
711
731
 
712
- // Assure the compiler that matches didn't become null during the async
713
- // operation above.
714
- goog.asserts.assert(matches, 'Matches should be non-null');
715
-
716
- shaka.util.PeriodCombiner.extendOutputStream_(
717
- outputStream, matches, /* firstNewPeriodIndex= */ 0, concat,
718
- unusedStreamsPerPeriod);
732
+ if (!outputStream.matchedStreams) {
733
+ // This is not a stream we can build output from, but it may become part
734
+ // of another output based on another period's stream.
735
+ return null;
736
+ }
737
+ shaka.util.PeriodCombiner.extendOutputStream_(outputStream,
738
+ /* firstNewPeriodIndex= */ 0, concat, unusedStreamsPerPeriod);
719
739
 
720
740
  return outputStream;
721
741
  }
@@ -723,7 +743,6 @@ shaka.util.PeriodCombiner = class {
723
743
  /**
724
744
  * @param {T} outputStream An existing output stream which needs to be
725
745
  * extended into new periods.
726
- * @param {!Array.<T>} matches A list of matching Streams from each period.
727
746
  * @param {number} firstNewPeriodIndex An index into streamsPerPeriod which
728
747
  * represents the first new period that hasn't been processed yet.
729
748
  * @param {function(T, T)} concat Concatenate the second stream onto the end
@@ -737,10 +756,15 @@ shaka.util.PeriodCombiner = class {
737
756
  * @private
738
757
  */
739
758
  static extendOutputStream_(
740
- outputStream, matches, firstNewPeriodIndex, concat,
741
- unusedStreamsPerPeriod) {
759
+ outputStream, firstNewPeriodIndex, concat, unusedStreamsPerPeriod) {
742
760
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
743
761
  const LanguageUtils = shaka.util.LanguageUtils;
762
+ const matches = outputStream.matchedStreams;
763
+
764
+ // Assure the compiler that matches didn't become null during the async
765
+ // operation before.
766
+ goog.asserts.assert(outputStream.matchedStreams,
767
+ 'matchedStreams should be non-null');
744
768
 
745
769
  // Concatenate the new matches onto the stream, starting at the first new
746
770
  // period.
@@ -784,7 +808,23 @@ shaka.util.PeriodCombiner = class {
784
808
  // streams that match this output.
785
809
  clone.originalId = null;
786
810
  clone.createSegmentIndex = () => Promise.resolve();
787
- clone.segmentIndex = new shaka.media.MetaSegmentIndex();
811
+ clone.closeSegmentIndex = () => {
812
+ if (clone.segmentIndex) {
813
+ clone.segmentIndex.release();
814
+ clone.segmentIndex = null;
815
+ }
816
+ // Close the segment index of the matched streams.
817
+ if (clone.matchedStreams) {
818
+ for (const match of clone.matchedStreams) {
819
+ if (match.segmentIndex) {
820
+ match.segmentIndex.release();
821
+ match.segmentIndex = null;
822
+ }
823
+ }
824
+ }
825
+ };
826
+
827
+ clone.segmentIndex = null;
788
828
  clone.emsgSchemeIdUris = [];
789
829
  clone.keyIds = new Set();
790
830
  clone.closedCaptions = null;
@@ -870,26 +910,24 @@ shaka.util.PeriodCombiner = class {
870
910
  }
871
911
  }
872
912
 
873
- // Satisfy the compiler about the type.
874
- goog.asserts.assert(
875
- output.segmentIndex instanceof shaka.media.MetaSegmentIndex,
876
- 'Output streams should have a MetaSegmentIndex!');
877
- // Satisfy the compiler that the input index has been created.
878
- goog.asserts.assert(
879
- input.segmentIndex,
880
- 'Input segment index should have been created by now!');
881
-
882
- output.segmentIndex.appendSegmentIndex(input.segmentIndex);
883
-
884
913
  // Combine trick-play video streams, if present.
885
914
  if (input.trickModeVideo) {
886
915
  if (!output.trickModeVideo) {
887
916
  // Create a fresh output stream for trick-mode playback.
888
917
  output.trickModeVideo = shaka.util.PeriodCombiner.cloneStream_(
889
918
  input.trickModeVideo);
890
- // Start it with whatever non-trick-mode Streams are in the output so
891
- // far.
892
- output.trickModeVideo.segmentIndex = output.segmentIndex.clone();
919
+ // TODO: fix the createSegmentIndex function for trickModeVideo.
920
+ // The trick-mode tracks in multi-period content should have trick-mode
921
+ // segment indexes whenever available, rather than only regular-mode
922
+ // segment indexes.
923
+ output.trickModeVideo.createSegmentIndex = () => {
924
+ // Satisfy the compiler about the type.
925
+ goog.asserts.assert(
926
+ output.segmentIndex instanceof shaka.media.MetaSegmentIndex,
927
+ 'The stream should have a MetaSegmentIndex.');
928
+ output.trickModeVideo.segmentIndex = output.segmentIndex.clone();
929
+ return Promise.resolve();
930
+ };
893
931
  }
894
932
 
895
933
  // Concatenate the trick mode input onto the trick mode output.
@@ -940,7 +978,6 @@ shaka.util.PeriodCombiner = class {
940
978
  *
941
979
  * @param {!Array.<!Array.<T>>} streamsPerPeriod
942
980
  * @param {T} outputStream
943
- * @return {Array.<T>}
944
981
  *
945
982
  * @template T
946
983
  * Accepts either a StreamDB or Stream type.
@@ -953,11 +990,11 @@ shaka.util.PeriodCombiner = class {
953
990
  const match = shaka.util.PeriodCombiner.findBestMatchInPeriod_(
954
991
  streams, outputStream);
955
992
  if (!match) {
956
- return null;
993
+ return;
957
994
  }
958
995
  matches.push(match);
959
996
  }
960
- return matches;
997
+ outputStream.matchedStreams = matches;
961
998
  }
962
999
 
963
1000
  /**
@@ -163,7 +163,6 @@ shaka.util.Platform = class {
163
163
  !shaka.util.Platform.isEdge();
164
164
  }
165
165
 
166
-
167
166
  /**
168
167
  * Check if the current platform is from Apple.
169
168
  *
@@ -179,6 +178,19 @@ shaka.util.Platform = class {
179
178
  && !shaka.util.Platform.isTizen();
180
179
  }
181
180
 
181
+ /**
182
+ * Check if the current platform is Playstation 5.
183
+ *
184
+ * Returns true on Playstation 5 browsers.
185
+ *
186
+ * Returns false for Playstation 5 browsers
187
+ *
188
+ * @return {boolean}
189
+ */
190
+ static isPS5() {
191
+ return shaka.util.Platform.userAgentContains_('PlayStation 5');
192
+ }
193
+
182
194
  /**
183
195
  * Returns a major version number for Safari, or Safari-based iOS browsers.
184
196
  *
@@ -120,6 +120,8 @@ shaka.util.PlayerConfiguration = class {
120
120
  ignoreTextStreamFailures: false,
121
121
  ignoreImageStreamFailures: false,
122
122
  useFullSegmentsForStartTime: false,
123
+ defaultAudioCodec: 'mp4a.40.2',
124
+ defaultVideoCodec: 'avc1.42E01E',
123
125
  },
124
126
  };
125
127
 
@@ -163,6 +165,8 @@ shaka.util.PlayerConfiguration = class {
163
165
  forceHTTPS: false,
164
166
  preferNativeHls: false,
165
167
  updateIntervalSeconds: 1,
168
+ dispatchAllEmsgBoxes: false,
169
+ observeQualityChanges: false,
166
170
  };
167
171
 
168
172
  // Some browsers will stop earlier than others before a gap (e.g., Edge
@@ -235,6 +239,19 @@ shaka.util.PlayerConfiguration = class {
235
239
  minBandwidth: 0,
236
240
  maxBandwidth: Infinity,
237
241
  },
242
+ advanced: {
243
+ minTotalBytes: 128e3,
244
+ minBytes: 16e3,
245
+ fastHalfLife: 2,
246
+ slowHalfLife: 5,
247
+ },
248
+ };
249
+
250
+ const cmcd = {
251
+ enabled: false,
252
+ sessionId: '',
253
+ contentId: '',
254
+ useHeaders: false,
238
255
  };
239
256
 
240
257
  /** @type {shaka.extern.PlayerConfiguration} */
@@ -269,6 +286,7 @@ shaka.util.PlayerConfiguration = class {
269
286
  playRangeStart: 0,
270
287
  playRangeEnd: Infinity,
271
288
  textDisplayFactory: () => null,
289
+ cmcd: cmcd,
272
290
  };
273
291
 
274
292
  // Add this callback so that we can reference the preferred audio language