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
package/lib/util/error.js CHANGED
@@ -814,6 +814,12 @@ shaka.util.Error.Code = {
814
814
  */
815
815
  'INIT_DATA_TRANSFORM_ERROR': 6016,
816
816
 
817
+ /**
818
+ * The server certificate request failed.
819
+ * <br> error.data[0] is a shaka.util.Error from the networking engine.
820
+ */
821
+ 'SERVER_CERTIFICATE_REQUEST_FAILED': 6017,
822
+
817
823
 
818
824
  /**
819
825
  * The call to Player.load() was interrupted by a call to Player.unload()
@@ -980,6 +986,12 @@ shaka.util.Error.Code = {
980
986
  */
981
987
  'DOWNLOAD_SIZE_CALLBACK_ERROR': 9015,
982
988
 
989
+ /**
990
+ * The storage cell does not allow new operations that significantly change
991
+ * existing data.
992
+ */
993
+ 'MODIFY_OPERATION_NOT_SUPPORTED': 9016,
994
+
983
995
  /**
984
996
  * CS IMA SDK, required for ad insertion, has not been included on the page.
985
997
  */
@@ -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;
@@ -55,6 +55,7 @@ shaka.util.ManifestParserUtils = class {
55
55
  audioRobustness: '',
56
56
  videoRobustness: '',
57
57
  serverCertificate: null,
58
+ serverCertificateUri: '',
58
59
  sessionType: '',
59
60
  initData: initData || [],
60
61
  keyIds: new Set(),
@@ -14,7 +14,7 @@ shaka.util.Mp4BoxParsers = class {
14
14
  /**
15
15
  * Parses a TFHD Box.
16
16
  * @param {!shaka.util.DataViewReader} reader
17
- * @param {!number} flags
17
+ * @param {number} flags
18
18
  * @return {!shaka.util.ParsedTFHDBox}
19
19
  */
20
20
  static parseTFHD(reader, flags) {
@@ -53,7 +53,7 @@ shaka.util.Mp4BoxParsers = class {
53
53
  /**
54
54
  * Parses a TFDT Box.
55
55
  * @param {!shaka.util.DataViewReader} reader
56
- * @param {!number} version
56
+ * @param {number} version
57
57
  * @return {!shaka.util.ParsedTFDTBox}
58
58
  */
59
59
  static parseTFDT(reader, version) {
@@ -68,7 +68,7 @@ shaka.util.Mp4BoxParsers = class {
68
68
  /**
69
69
  * Parses a MDHD Box.
70
70
  * @param {!shaka.util.DataViewReader} reader
71
- * @param {!number} version
71
+ * @param {number} version
72
72
  * @return {!shaka.util.ParsedMDHDBox}
73
73
  */
74
74
  static parseMDHD(reader, version) {
@@ -107,8 +107,8 @@ shaka.util.Mp4BoxParsers = class {
107
107
  /**
108
108
  * Parses a TRUN Box.
109
109
  * @param {!shaka.util.DataViewReader} reader
110
- * @param {!number} version
111
- * @param {!number} flags
110
+ * @param {number} version
111
+ * @param {number} flags
112
112
  * @return {!shaka.util.ParsedTRUNBox}
113
113
  */
114
114
  static parseTRUN(reader, version, flags) {
@@ -168,7 +168,7 @@ shaka.util.Mp4BoxParsers = class {
168
168
  /**
169
169
  * Parses a TKHD Box.
170
170
  * @param {!shaka.util.DataViewReader} reader
171
- * @param {!number} version
171
+ * @param {number} version
172
172
  * @return {!shaka.util.ParsedTKHDBox}
173
173
  */
174
174
  static parseTKHD(reader, version) {
@@ -192,12 +192,12 @@ shaka.util.Mp4BoxParsers = class {
192
192
 
193
193
  /**
194
194
  * @typedef {{
195
- * trackId: !number,
195
+ * trackId: number,
196
196
  * defaultSampleDuration: ?number,
197
197
  * defaultSampleSize: ?number
198
198
  * }}
199
199
  *
200
- * @property {!number} trackId
200
+ * @property {number} trackId
201
201
  * As per the spec: an integer that uniquely identifies this
202
202
  * track over the entire life‐time of this presentation
203
203
  * @property {?number} defaultSampleDuration
@@ -213,10 +213,10 @@ shaka.util.ParsedTFHDBox;
213
213
 
214
214
  /**
215
215
  * @typedef {{
216
- * baseMediaDecodeTime: !number
216
+ * baseMediaDecodeTime: number
217
217
  * }}
218
218
  *
219
- * @property {!number} baseMediaDecodeTime
219
+ * @property {number} baseMediaDecodeTime
220
220
  * As per the spec: the absolute decode time, measured on the media
221
221
  * timeline, of the first sample in decode order in the track fragment
222
222
  *
@@ -226,10 +226,10 @@ shaka.util.ParsedTFDTBox;
226
226
 
227
227
  /**
228
228
  * @typedef {{
229
- * timescale: !number
229
+ * timescale: number
230
230
  * }}
231
231
  *
232
- * @property {!number} timescale
232
+ * @property {number} timescale
233
233
  * As per the spec: an integer that specifies the time‐scale for this media;
234
234
  * this is the number of time units that pass in one second
235
235
  *
@@ -239,13 +239,13 @@ shaka.util.ParsedMDHDBox;
239
239
 
240
240
  /**
241
241
  * @typedef {{
242
- * defaultSampleDuration: !number,
243
- * defaultSampleSize: !number
242
+ * defaultSampleDuration: number,
243
+ * defaultSampleSize: number
244
244
  * }}
245
245
  *
246
- * @property {!number} defaultSampleDuration
246
+ * @property {number} defaultSampleDuration
247
247
  * The default sample duration to be used in track fragments
248
- * @property {!number} defaultSampleSize
248
+ * @property {number} defaultSampleSize
249
249
  * The default sample size to be used in track fragments
250
250
  *
251
251
  * @exportDoc
@@ -254,11 +254,11 @@ shaka.util.ParsedTREXBox;
254
254
 
255
255
  /**
256
256
  * @typedef {{
257
- * sampleCount: !number,
257
+ * sampleCount: number,
258
258
  * sampleData: !Array.<shaka.util.ParsedTRUNSample>
259
259
  * }}
260
260
  *
261
- * @property {!number} sampleCount
261
+ * @property {number} sampleCount
262
262
  * As per the spec: the number of samples being added in this run;
263
263
  * @property {!Array.<shaka.util.ParsedTRUNSample>} sampleData
264
264
  * An array of size <sampleCount> containing data for each sample
@@ -290,10 +290,10 @@ shaka.util.ParsedTRUNSample;
290
290
 
291
291
  /**
292
292
  * @typedef {{
293
- * trackId: !number
293
+ * trackId: number
294
294
  * }}
295
295
  *
296
- * @property {!number} trackId
296
+ * @property {number} trackId
297
297
  * Unique ID indicative of this track
298
298
  *
299
299
  * @exportDoc
@@ -102,4 +102,12 @@ shaka.util.MultiMap = class {
102
102
  size() {
103
103
  return Object.keys(this.map_).length;
104
104
  }
105
+
106
+ /**
107
+ * Get a list of all the keys.
108
+ * @return {!Array.<string>}
109
+ */
110
+ keys() {
111
+ return Object.keys(this.map_);
112
+ }
105
113
  };
@@ -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
+ };
@@ -547,8 +547,7 @@ shaka.util.PeriodCombiner = class {
547
547
  for (const stream of unusedStreams) {
548
548
  // Create a new output stream which includes this input stream.
549
549
  const outputStream =
550
- // eslint-disable-next-line no-await-in-loop
551
- await shaka.util.PeriodCombiner.createNewOutputStream_(
550
+ shaka.util.PeriodCombiner.createNewOutputStream_(
552
551
  stream, streamsPerPeriod, clone, concat,
553
552
  unusedStreamsPerPeriod);
554
553
  if (outputStream) {
@@ -619,52 +618,69 @@ shaka.util.PeriodCombiner = class {
619
618
  static async extendExistingOutputStream_(
620
619
  outputStream, streamsPerPeriod, firstNewPeriodIndex, concat,
621
620
  unusedStreamsPerPeriod) {
622
- const matches = shaka.util.PeriodCombiner.findMatchesInAllPeriods_(
623
- streamsPerPeriod, outputStream);
624
-
625
- if (!matches) {
626
- // We were unable to extend this output stream.
627
- shaka.log.error('No matches extending output stream!',
628
- outputStream, streamsPerPeriod);
629
- return false;
630
- }
621
+ shaka.util.PeriodCombiner.findMatchesInAllPeriods_(streamsPerPeriod,
622
+ outputStream);
631
623
 
632
624
  // This only exists where T == Stream, and this should only ever be called
633
625
  // on Stream types. StreamDB should not have pre-existing output streams.
634
626
  goog.asserts.assert(outputStream.createSegmentIndex,
635
627
  'outputStream should be a Stream type!');
636
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
+ }
637
635
  // We need to create all the per-period segment indexes and append them to
638
636
  // the output's MetaSegmentIndex.
639
- await shaka.util.PeriodCombiner.createSegmentIndexes_(matches);
640
-
641
- // Assure the compiler that matches didn't become null during the async
642
- // operation above.
643
- goog.asserts.assert(matches, 'Matches should be non-null');
637
+ if (outputStream.segmentIndex) {
638
+ await shaka.util.PeriodCombiner.extendOutputSegmentIndex_(outputStream,
639
+ firstNewPeriodIndex);
640
+ }
644
641
 
645
- shaka.util.PeriodCombiner.extendOutputStream_(
646
- outputStream, matches, firstNewPeriodIndex, concat,
647
- unusedStreamsPerPeriod);
642
+ shaka.util.PeriodCombiner.extendOutputStream_(outputStream,
643
+ firstNewPeriodIndex, concat, unusedStreamsPerPeriod);
648
644
  return true;
649
645
  }
650
646
 
651
647
  /**
652
- * Creates all segment indexes for an array of streams. Returns once every
653
- * 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.
654
650
  *
655
- * @param {!Array.<!shaka.extern.Stream>} streams
656
- * @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.
657
654
  * @private
658
655
  */
659
- static createSegmentIndexes_(streams) {
656
+ static async extendOutputSegmentIndex_(outputStream, firstNewPeriodIndex) {
660
657
  const operations = [];
658
+ const streams = outputStream.matchedStreams;
659
+ goog.asserts.assert(streams, 'matched streams should be valid');
660
+
661
661
  for (const stream of streams) {
662
662
  operations.push(stream.createSegmentIndex());
663
663
  if (stream.trickModeVideo && !stream.trickModeVideo.segmentIndex) {
664
664
  operations.push(stream.trickModeVideo.createSegmentIndex());
665
665
  }
666
666
  }
667
- 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
+ }
668
684
  }
669
685
 
670
686
  /**
@@ -682,7 +698,7 @@ shaka.util.PeriodCombiner = class {
682
698
  * @param {!Array.<!Set.<T>>} unusedStreamsPerPeriod An array of sets of
683
699
  * unused streams from each period.
684
700
  *
685
- * @return {!Promise.<?T>} A newly-created output Stream, or null if matches
701
+ * @return {?T} A newly-created output Stream, or null if matches
686
702
  * could not be found.`
687
703
  *
688
704
  * @template T
@@ -690,35 +706,36 @@ shaka.util.PeriodCombiner = class {
690
706
  *
691
707
  * @private
692
708
  */
693
- static async createNewOutputStream_(
709
+ static createNewOutputStream_(
694
710
  stream, streamsPerPeriod, clone, concat, unusedStreamsPerPeriod) {
695
711
  // Start by cloning the stream without segments, key IDs, etc.
696
712
  const outputStream = clone(stream);
697
713
 
698
714
  // Find best-matching streams in all periods.
699
- const matches = shaka.util.PeriodCombiner.findMatchesInAllPeriods_(
700
- streamsPerPeriod, outputStream);
701
-
702
- if (!matches) {
703
- // This is not a stream we can build output from, but it may become part
704
- // of another output based on another period's stream.
705
- return null;
706
- }
715
+ shaka.util.PeriodCombiner.findMatchesInAllPeriods_(streamsPerPeriod,
716
+ outputStream);
707
717
 
708
718
  // This only exists where T == Stream.
709
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
+ };
710
728
  // For T == Stream, we need to create all the per-period segment indexes
711
729
  // in advance. concat() will add them to the output's MetaSegmentIndex.
712
- await shaka.util.PeriodCombiner.createSegmentIndexes_(matches);
713
730
  }
714
731
 
715
- // Assure the compiler that matches didn't become null during the async
716
- // operation above.
717
- goog.asserts.assert(matches, 'Matches should be non-null');
718
-
719
- shaka.util.PeriodCombiner.extendOutputStream_(
720
- outputStream, matches, /* firstNewPeriodIndex= */ 0, concat,
721
- 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);
722
739
 
723
740
  return outputStream;
724
741
  }
@@ -726,7 +743,6 @@ shaka.util.PeriodCombiner = class {
726
743
  /**
727
744
  * @param {T} outputStream An existing output stream which needs to be
728
745
  * extended into new periods.
729
- * @param {!Array.<T>} matches A list of matching Streams from each period.
730
746
  * @param {number} firstNewPeriodIndex An index into streamsPerPeriod which
731
747
  * represents the first new period that hasn't been processed yet.
732
748
  * @param {function(T, T)} concat Concatenate the second stream onto the end
@@ -740,10 +756,15 @@ shaka.util.PeriodCombiner = class {
740
756
  * @private
741
757
  */
742
758
  static extendOutputStream_(
743
- outputStream, matches, firstNewPeriodIndex, concat,
744
- unusedStreamsPerPeriod) {
759
+ outputStream, firstNewPeriodIndex, concat, unusedStreamsPerPeriod) {
745
760
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
746
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');
747
768
 
748
769
  // Concatenate the new matches onto the stream, starting at the first new
749
770
  // period.
@@ -787,7 +808,23 @@ shaka.util.PeriodCombiner = class {
787
808
  // streams that match this output.
788
809
  clone.originalId = null;
789
810
  clone.createSegmentIndex = () => Promise.resolve();
790
- 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;
791
828
  clone.emsgSchemeIdUris = [];
792
829
  clone.keyIds = new Set();
793
830
  clone.closedCaptions = null;
@@ -873,26 +910,24 @@ shaka.util.PeriodCombiner = class {
873
910
  }
874
911
  }
875
912
 
876
- // Satisfy the compiler about the type.
877
- goog.asserts.assert(
878
- output.segmentIndex instanceof shaka.media.MetaSegmentIndex,
879
- 'Output streams should have a MetaSegmentIndex!');
880
- // Satisfy the compiler that the input index has been created.
881
- goog.asserts.assert(
882
- input.segmentIndex,
883
- 'Input segment index should have been created by now!');
884
-
885
- output.segmentIndex.appendSegmentIndex(input.segmentIndex);
886
-
887
913
  // Combine trick-play video streams, if present.
888
914
  if (input.trickModeVideo) {
889
915
  if (!output.trickModeVideo) {
890
916
  // Create a fresh output stream for trick-mode playback.
891
917
  output.trickModeVideo = shaka.util.PeriodCombiner.cloneStream_(
892
918
  input.trickModeVideo);
893
- // Start it with whatever non-trick-mode Streams are in the output so
894
- // far.
895
- 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
+ };
896
931
  }
897
932
 
898
933
  // Concatenate the trick mode input onto the trick mode output.
@@ -943,7 +978,6 @@ shaka.util.PeriodCombiner = class {
943
978
  *
944
979
  * @param {!Array.<!Array.<T>>} streamsPerPeriod
945
980
  * @param {T} outputStream
946
- * @return {Array.<T>}
947
981
  *
948
982
  * @template T
949
983
  * Accepts either a StreamDB or Stream type.
@@ -956,11 +990,11 @@ shaka.util.PeriodCombiner = class {
956
990
  const match = shaka.util.PeriodCombiner.findBestMatchInPeriod_(
957
991
  streams, outputStream);
958
992
  if (!match) {
959
- return null;
993
+ return;
960
994
  }
961
995
  matches.push(match);
962
996
  }
963
- return matches;
997
+ outputStream.matchedStreams = matches;
964
998
  }
965
999
 
966
1000
  /**
@@ -75,6 +75,7 @@ shaka.util.PlayerConfiguration = class {
75
75
  initDataTransform: shaka.media.DrmEngine.defaultInitDataTransform,
76
76
  logLicenseExchange: false,
77
77
  updateExpirationTime: 1,
78
+ preferredKeySystems: [],
78
79
  };
79
80
 
80
81
  const manifest = {
@@ -108,10 +109,19 @@ shaka.util.PlayerConfiguration = class {
108
109
  'urn:uuid:f239e769-efa3-4850-9c16-a903c6932efb':
109
110
  'com.adobe.primetime',
110
111
  },
112
+ // Need some operation in the callback or else closure may remove calls
113
+ // to the function as it would be a no-op. The operation can't just be
114
+ // a log message, because those are stripped in the compiled build.
115
+ manifestPreprocessor: (element) => {
116
+ return element;
117
+ },
111
118
  },
112
119
  hls: {
113
120
  ignoreTextStreamFailures: false,
121
+ ignoreImageStreamFailures: false,
114
122
  useFullSegmentsForStartTime: false,
123
+ defaultAudioCodec: 'mp4a.40.2',
124
+ defaultVideoCodec: 'avc1.42E01E',
115
125
  },
116
126
  };
117
127
 
@@ -154,6 +164,9 @@ shaka.util.PlayerConfiguration = class {
154
164
  autoLowLatencyMode: false,
155
165
  forceHTTPS: false,
156
166
  preferNativeHls: false,
167
+ updateIntervalSeconds: 1,
168
+ dispatchAllEmsgBoxes: false,
169
+ observeQualityChanges: false,
157
170
  };
158
171
 
159
172
  // Some browsers will stop earlier than others before a gap (e.g., Edge
@@ -226,6 +239,19 @@ shaka.util.PlayerConfiguration = class {
226
239
  minBandwidth: 0,
227
240
  maxBandwidth: Infinity,
228
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,
229
255
  };
230
256
 
231
257
  /** @type {shaka.extern.PlayerConfiguration} */
@@ -241,7 +267,10 @@ shaka.util.PlayerConfiguration = class {
241
267
  preferredVariantRole: '',
242
268
  preferredTextRole: '',
243
269
  preferredAudioChannelCount: 2,
270
+ preferredVideoCodecs: [],
271
+ preferredAudioCodecs: [],
244
272
  preferForcedSubs: false,
273
+ preferredDecodingAttributes: [],
245
274
  restrictions: {
246
275
  minWidth: 0,
247
276
  maxWidth: Infinity,
@@ -256,8 +285,8 @@ shaka.util.PlayerConfiguration = class {
256
285
  },
257
286
  playRangeStart: 0,
258
287
  playRangeEnd: Infinity,
259
- useMediaCapabilities: false,
260
288
  textDisplayFactory: () => null,
289
+ cmcd: cmcd,
261
290
  };
262
291
 
263
292
  // Add this callback so that we can reference the preferred audio language
@@ -293,6 +322,7 @@ shaka.util.PlayerConfiguration = class {
293
322
  audioRobustness: '',
294
323
  sessionType: '',
295
324
  serverCertificate: new Uint8Array(0),
325
+ serverCertificateUri: '',
296
326
  individualizationServer: '',
297
327
  },
298
328
  };