shaka-player 4.13.0 → 4.13.2

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 (67) hide show
  1. package/CONTRIBUTORS +1 -0
  2. package/dist/deps.js +4 -4
  3. package/dist/locales.js +36 -36
  4. package/dist/shaka-player.compiled.d.ts +1 -1
  5. package/dist/shaka-player.compiled.debug.d.ts +1 -1
  6. package/dist/shaka-player.compiled.debug.externs.js +2 -9
  7. package/dist/shaka-player.compiled.debug.js +491 -478
  8. package/dist/shaka-player.compiled.debug.map +4 -4
  9. package/dist/shaka-player.compiled.externs.js +2 -9
  10. package/dist/shaka-player.compiled.js +1455 -1443
  11. package/dist/shaka-player.compiled.map +4 -4
  12. package/dist/shaka-player.ui.d.ts +1 -1
  13. package/dist/shaka-player.ui.debug.d.ts +1 -1
  14. package/dist/shaka-player.ui.debug.externs.js +2 -9
  15. package/dist/shaka-player.ui.debug.js +544 -530
  16. package/dist/shaka-player.ui.debug.map +4 -4
  17. package/dist/shaka-player.ui.externs.js +2 -9
  18. package/dist/shaka-player.ui.js +1627 -1613
  19. package/dist/shaka-player.ui.map +4 -4
  20. package/eslint.config.mjs +14 -1
  21. package/lib/cast/cast_proxy.js +50 -12
  22. package/lib/cast/cast_receiver.js +6 -9
  23. package/lib/cast/cast_sender.js +14 -11
  24. package/lib/cast/cast_utils.js +43 -46
  25. package/lib/cea/mp4_cea_parser.js +23 -23
  26. package/lib/dash/content_protection.js +1 -1
  27. package/lib/dash/dash_parser.js +39 -29
  28. package/lib/dash/mpd_utils.js +8 -9
  29. package/lib/dash/segment_list.js +2 -2
  30. package/lib/dash/segment_template.js +9 -9
  31. package/lib/debug/log.js +16 -17
  32. package/lib/hls/hls_parser.js +122 -99
  33. package/lib/media/closed_caption_parser.js +5 -5
  34. package/lib/media/content_workarounds.js +78 -0
  35. package/lib/media/example_based_criteria.js +4 -3
  36. package/lib/media/manifest_parser.js +8 -12
  37. package/lib/media/media_source_engine.js +136 -119
  38. package/lib/media/preload_manager.js +10 -5
  39. package/lib/media/region_observer.js +9 -8
  40. package/lib/media/region_timeline.js +10 -8
  41. package/lib/media/streaming_engine.js +25 -9
  42. package/lib/mss/mss_parser.js +6 -7
  43. package/lib/net/http_plugin_utils.js +1 -1
  44. package/lib/net/networking_engine.js +7 -7
  45. package/lib/net/networking_utils.js +38 -39
  46. package/lib/offline/stream_bandwidth_estimator.js +8 -8
  47. package/lib/player.js +98 -47
  48. package/lib/polyfill/media_capabilities.js +8 -9
  49. package/lib/text/cue.js +6 -2
  50. package/lib/text/text_engine.js +7 -7
  51. package/lib/text/ttml_text_parser.js +14 -16
  52. package/lib/text/ui_text_displayer.js +25 -4
  53. package/lib/transmuxer/ac3_transmuxer.js +6 -1
  54. package/lib/transmuxer/transmuxer_engine.js +6 -6
  55. package/lib/util/manifest_parser_utils.js +7 -8
  56. package/lib/util/mp4_generator.js +23 -8
  57. package/lib/util/mp4_parser.js +10 -10
  58. package/lib/util/multi_map.js +22 -20
  59. package/lib/util/platform.js +40 -9
  60. package/lib/util/player_configuration.js +1 -1
  61. package/lib/util/stream_utils.js +35 -17
  62. package/package.json +2 -2
  63. package/project-words.txt +1 -0
  64. package/third_party/closure-uri/uri.js +13 -13
  65. package/ui/ad_statistics_button.js +17 -16
  66. package/ui/audio_language_selection.js +6 -1
  67. package/ui/statistics_button.js +36 -35
@@ -37,14 +37,13 @@ shaka.dash.MpdUtils = class {
37
37
  */
38
38
  static fillUriTemplate(
39
39
  uriTemplate, representationId, number, subNumber, bandwidth, time) {
40
- /** @type {!Object<string, ?number | ?string>} */
41
- const valueTable = {
42
- 'RepresentationID': representationId,
43
- 'Number': number,
44
- 'SubNumber': subNumber,
45
- 'Bandwidth': bandwidth,
46
- 'Time': time,
47
- };
40
+ /** @type {!Map<string, ?number | ?string>} */
41
+ const valueTable = new Map()
42
+ .set('RepresentationID', representationId)
43
+ .set('Number', number)
44
+ .set('SubNumber', subNumber)
45
+ .set('Bandwidth', bandwidth)
46
+ .set('Time', time);
48
47
 
49
48
  // cspell: disable-next-line
50
49
  const re = /\$(RepresentationID|Number|SubNumber|Bandwidth|Time)?(?:%0([0-9]+)([diouxX]))?\$/g; // eslint-disable-line max-len
@@ -53,7 +52,7 @@ shaka.dash.MpdUtils = class {
53
52
  return '$';
54
53
  }
55
54
 
56
- let value = valueTable[name];
55
+ let value = valueTable.get(name);
57
56
  goog.asserts.assert(value !== undefined, 'Unrecognized identifier');
58
57
 
59
58
  // Note that |value| may be 0 or ''.
@@ -31,7 +31,7 @@ shaka.dash.SegmentList = class {
31
31
  * Updates the existing SegmentIndex, if any.
32
32
  *
33
33
  * @param {shaka.dash.DashParser.Context} context
34
- * @param {!Object<string, !shaka.extern.Stream>} streamMap
34
+ * @param {!Map<string, !shaka.extern.Stream>} streamMap
35
35
  * @param {shaka.extern.aesKey|undefined} aesKey
36
36
  * @return {shaka.dash.DashParser.StreamInfo}
37
37
  */
@@ -52,7 +52,7 @@ shaka.dash.SegmentList = class {
52
52
  if (context.period.id && context.representation.id) {
53
53
  // Only check/store the index if period and representation IDs are set.
54
54
  const id = context.period.id + ',' + context.representation.id;
55
- stream = streamMap[id];
55
+ stream = streamMap.get(id);
56
56
  if (stream) {
57
57
  segmentIndex = stream.segmentIndex;
58
58
  }
@@ -33,11 +33,11 @@ shaka.dash.SegmentTemplate = class {
33
33
  *
34
34
  * @param {shaka.dash.DashParser.Context} context
35
35
  * @param {shaka.dash.DashParser.RequestSegmentCallback} requestSegment
36
- * @param {!Object<string, !shaka.extern.Stream>} streamMap
36
+ * @param {!Map<string, !shaka.extern.Stream>} streamMap
37
37
  * @param {boolean} isUpdate True if the manifest is being updated.
38
38
  * @param {number} segmentLimit The maximum number of segments to generate for
39
39
  * a SegmentTemplate with fixed duration.
40
- * @param {!Object<string, number>} periodDurationMap
40
+ * @param {!Map<string, number>} periodDurationMap
41
41
  * @param {shaka.extern.aesKey|undefined} aesKey
42
42
  * @param {?number} lastSegmentNumber
43
43
  * @param {boolean} isPatchUpdate
@@ -92,7 +92,7 @@ shaka.dash.SegmentTemplate = class {
92
92
  const periodId = context.period.id;
93
93
  const initialPeriodDuration = context.periodInfo.duration;
94
94
  const periodDuration =
95
- (periodId != null && periodDurationMap[periodId]) ||
95
+ (periodId != null && periodDurationMap.get(periodId)) ||
96
96
  initialPeriodDuration;
97
97
  const periodEnd = periodDuration ?
98
98
  (periodStart + periodDuration) : Infinity;
@@ -119,7 +119,7 @@ shaka.dash.SegmentTemplate = class {
119
119
  if (context.period.id && context.representation.id) {
120
120
  // Only check/store the index if period and representation IDs are set.
121
121
  id = context.period.id + ',' + context.representation.id;
122
- stream = streamMap[id];
122
+ stream = streamMap.get(id);
123
123
  if (stream) {
124
124
  segmentIndex = stream.segmentIndex;
125
125
  }
@@ -135,7 +135,7 @@ shaka.dash.SegmentTemplate = class {
135
135
  shaka.log.debug(`Creating TSI with end ${periodEnd}`);
136
136
  segmentIndex = new TimelineSegmentIndex(
137
137
  info,
138
- context.representation.id,
138
+ context.representation.originalId,
139
139
  context.bandwidth,
140
140
  context.representation.getBaseUris,
141
141
  context.urlParams,
@@ -348,7 +348,7 @@ shaka.dash.SegmentTemplate = class {
348
348
 
349
349
  goog.asserts.assert(info.indexTemplate, 'must be using index template');
350
350
  const filledTemplate = MpdUtils.fillUriTemplate(
351
- info.indexTemplate, context.representation.id,
351
+ info.indexTemplate, context.representation.originalId,
352
352
  null, null, context.bandwidth || null, null);
353
353
 
354
354
  const resolvedUris = ManifestParserUtils.resolveUris(
@@ -366,7 +366,7 @@ shaka.dash.SegmentTemplate = class {
366
366
  * @param {shaka.dash.SegmentTemplate.SegmentTemplateInfo} info
367
367
  * @param {number} segmentLimit The maximum number of segments to generate.
368
368
  * @param {shaka.media.InitSegmentReference} initSegmentReference
369
- * @param {!Object<string, number>} periodDurationMap
369
+ * @param {!Map<string, number>} periodDurationMap
370
370
  * @param {shaka.extern.aesKey|undefined} aesKey
371
371
  * @param {?number} lastSegmentNumber
372
372
  * @param {number} segmentSequenceCadence
@@ -395,7 +395,7 @@ shaka.dash.SegmentTemplate = class {
395
395
  // provides the updated period duration.
396
396
  const getPeriodEnd = () => {
397
397
  const periodDuration =
398
- (periodId != null && periodDurationMap[periodId]) ||
398
+ (periodId != null && periodDurationMap.get(periodId)) ||
399
399
  initialPeriodDuration;
400
400
  const periodEnd = periodDuration ?
401
401
  (periodStart + periodDuration) : Infinity;
@@ -677,7 +677,7 @@ shaka.dash.SegmentTemplate = class {
677
677
  }
678
678
  initialization = shaka.util.StringUtils.htmlUnescape(initialization);
679
679
 
680
- const repId = context.representation.id;
680
+ const repId = context.representation.originalId;
681
681
  const bandwidth = context.bandwidth || null;
682
682
  const getBaseUris = context.representation.getBaseUris;
683
683
  const urlParams = context.urlParams;
package/lib/debug/log.js CHANGED
@@ -135,15 +135,14 @@ shaka.log.oneTimeWarningIssued_ = new Set();
135
135
 
136
136
 
137
137
  if (window.console) {
138
- /** @private {!Object<shaka.log.Level, function(...*)>} */
139
- shaka.log.logMap_ = {
140
- [shaka.log.Level.ERROR]: (...args) => console.error(...args),
141
- [shaka.log.Level.WARNING]: (...args) => console.warn(...args),
142
- [shaka.log.Level.INFO]: (...args) => console.info(...args),
143
- [shaka.log.Level.DEBUG]: (...args) => console.log(...args),
144
- [shaka.log.Level.V1]: (...args) => console.debug(...args),
145
- [shaka.log.Level.V2]: (...args) => console.debug(...args),
146
- };
138
+ /** @private {!Map<shaka.log.Level, function(...*)>} */
139
+ shaka.log.logMap_ = new Map()
140
+ .set(shaka.log.Level.ERROR, (...args) => console.error(...args))
141
+ .set(shaka.log.Level.WARNING, (...args) => console.warn(...args))
142
+ .set(shaka.log.Level.INFO, (...args) => console.info(...args))
143
+ .set(shaka.log.Level.DEBUG, (...args) => console.log(...args))
144
+ .set(shaka.log.Level.V1, (...args) => console.debug(...args))
145
+ .set(shaka.log.Level.V2, (...args) => console.debug(...args));
147
146
 
148
147
  shaka.log.alwaysWarn = (...args) => console.warn(...args);
149
148
  shaka.log.alwaysError = (...args) => console.error(...args);
@@ -168,8 +167,8 @@ if (window.console) {
168
167
  const getLog = (curLevel) => {
169
168
  if (curLevel <= level) {
170
169
  goog.asserts.assert(
171
- shaka.log.logMap_[curLevel], 'Unexpected log level');
172
- return shaka.log.logMap_[curLevel];
170
+ shaka.log.logMap_.has(curLevel), 'Unexpected log level');
171
+ return shaka.log.logMap_.get(curLevel);
173
172
  } else {
174
173
  return () => {};
175
174
  }
@@ -187,22 +186,22 @@ if (window.console) {
187
186
  shaka.log.setLevel(shaka.log.MAX_LOG_LEVEL);
188
187
  } else {
189
188
  if (shaka.log.MAX_LOG_LEVEL >= shaka.log.Level.ERROR) {
190
- shaka.log.error = shaka.log.logMap_[shaka.log.Level.ERROR];
189
+ shaka.log.error = shaka.log.logMap_.get(shaka.log.Level.ERROR);
191
190
  }
192
191
  if (shaka.log.MAX_LOG_LEVEL >= shaka.log.Level.WARNING) {
193
- shaka.log.warning = shaka.log.logMap_[shaka.log.Level.WARNING];
192
+ shaka.log.warning = shaka.log.logMap_.get(shaka.log.Level.WARNING);
194
193
  }
195
194
  if (shaka.log.MAX_LOG_LEVEL >= shaka.log.Level.INFO) {
196
- shaka.log.info = shaka.log.logMap_[shaka.log.Level.INFO];
195
+ shaka.log.info = shaka.log.logMap_.get(shaka.log.Level.INFO);
197
196
  }
198
197
  if (shaka.log.MAX_LOG_LEVEL >= shaka.log.Level.DEBUG) {
199
- shaka.log.debug = shaka.log.logMap_[shaka.log.Level.DEBUG];
198
+ shaka.log.debug = shaka.log.logMap_.get(shaka.log.Level.DEBUG);
200
199
  }
201
200
  if (shaka.log.MAX_LOG_LEVEL >= shaka.log.Level.V1) {
202
- shaka.log.v1 = shaka.log.logMap_[shaka.log.Level.V1];
201
+ shaka.log.v1 = shaka.log.logMap_.get(shaka.log.Level.V1);
203
202
  }
204
203
  if (shaka.log.MAX_LOG_LEVEL >= shaka.log.Level.V2) {
205
- shaka.log.v2 = shaka.log.logMap_[shaka.log.Level.V2];
204
+ shaka.log.v2 = shaka.log.logMap_.get(shaka.log.Level.V2);
206
205
  }
207
206
  }
208
207
  }
@@ -988,6 +988,31 @@ shaka.hls.HlsParser = class {
988
988
  new shaka.hls.Tag(tag.id, tag.name, newAttributes, null));
989
989
  }
990
990
  variantTags.push(...newVariantTags);
991
+
992
+ // Duplicate iFrame tags with supplementalCodecs
993
+ const newIFrameTags = [];
994
+ for (const tag of iFrameTags) {
995
+ const supplementalCodecsString =
996
+ tag.getAttributeValue('SUPPLEMENTAL-CODECS');
997
+ if (!supplementalCodecsString) {
998
+ continue;
999
+ }
1000
+ const supplementalCodecs = supplementalCodecsString.split(/\s*,\s*/)
1001
+ .map((codec) => {
1002
+ return codec.split('/')[0];
1003
+ });
1004
+ const newAttributes = tag.attributes.map((attr) => {
1005
+ const name = attr.name;
1006
+ let value = attr.value;
1007
+ if (name == 'CODECS') {
1008
+ value = supplementalCodecs.join(',');
1009
+ }
1010
+ return new shaka.hls.Attribute(name, value);
1011
+ });
1012
+ newIFrameTags.push(
1013
+ new shaka.hls.Tag(tag.id, tag.name, newAttributes, null));
1014
+ }
1015
+ iFrameTags.push(...newIFrameTags);
991
1016
  }
992
1017
 
993
1018
  this.parseCodecs_(variantTags);
@@ -1084,7 +1109,7 @@ shaka.hls.HlsParser = class {
1084
1109
  const segmentUri = segmentUris[0];
1085
1110
  const parsedUri = new goog.Uri(segmentUri);
1086
1111
  const extension = parsedUri.getPath().split('.').pop();
1087
- const rawMimeType = HlsParser.RAW_FORMATS_TO_MIME_TYPES_[extension];
1112
+ const rawMimeType = HlsParser.RAW_FORMATS_TO_MIME_TYPES_.get(extension);
1088
1113
  if (rawMimeType) {
1089
1114
  return shaka.media.SegmentUtils.getBasicInfoFromMimeType(
1090
1115
  rawMimeType);
@@ -1615,7 +1640,7 @@ shaka.hls.HlsParser = class {
1615
1640
  /* initSegmentRef= */ null, variables);
1616
1641
  } else {
1617
1642
  const drmParser =
1618
- shaka.hls.HlsParser.KEYFORMATS_TO_DRM_PARSERS_[keyFormat];
1643
+ shaka.hls.HlsParser.KEYFORMATS_TO_DRM_PARSERS_.get(keyFormat);
1619
1644
 
1620
1645
  drmInfo = drmParser ?
1621
1646
  drmParser(drmTag, /* mimeType= */ '') : null;
@@ -2386,12 +2411,13 @@ shaka.hls.HlsParser = class {
2386
2411
  return this.uriToStreamInfosMap_.get(key);
2387
2412
  }
2388
2413
 
2414
+ const name = verbatimMediaPlaylistUris.join(',');
2389
2415
  const closedCaptions = this.getClosedCaptions_(tags[0], type);
2390
2416
  const codecs = shaka.util.ManifestParserUtils.guessCodecs(type, allCodecs);
2391
2417
  const streamInfo = this.createStreamInfo_(
2392
2418
  streamId, verbatimMediaPlaylistUris,
2393
2419
  codecs, type, /* language= */ null, /* primary= */ false,
2394
- /* name= */ null, /* channelCount= */ null, closedCaptions,
2420
+ name, /* channelCount= */ null, closedCaptions,
2395
2421
  /* characteristics= */ null, /* forced= */ false,
2396
2422
  /* sampleRate= */ null, /* spatialAudio= */ false);
2397
2423
 
@@ -2438,21 +2464,11 @@ shaka.hls.HlsParser = class {
2438
2464
  this.setFullTypeForStream_(stream);
2439
2465
  }
2440
2466
 
2441
- const redirectUris = [];
2442
- const getUris = () => {
2443
- if (this.contentSteeringManager_ &&
2444
- verbatimMediaPlaylistUris.length > 1) {
2445
- return this.contentSteeringManager_.getLocations(streamId);
2446
- }
2447
- return redirectUris.concat(shaka.hls.Utils.constructUris(
2448
- [this.masterPlaylistUri_], verbatimMediaPlaylistUris,
2449
- this.globalVariables_));
2450
- };
2451
2467
  const streamInfo = {
2452
2468
  stream,
2453
2469
  type,
2454
- redirectUris,
2455
- getUris,
2470
+ redirectUris: [],
2471
+ getUris: () => {},
2456
2472
  // These values are filled out or updated after lazy-loading:
2457
2473
  minTimestamp: 0,
2458
2474
  maxTimestamp: 0,
@@ -2466,12 +2482,23 @@ shaka.hls.HlsParser = class {
2466
2482
  loadedOnce: false,
2467
2483
  };
2468
2484
 
2485
+ const getUris = () => {
2486
+ if (this.contentSteeringManager_ &&
2487
+ verbatimMediaPlaylistUris.length > 1) {
2488
+ return this.contentSteeringManager_.getLocations(streamId);
2489
+ }
2490
+ return streamInfo.redirectUris.concat(shaka.hls.Utils.constructUris(
2491
+ [this.masterPlaylistUri_], verbatimMediaPlaylistUris,
2492
+ this.globalVariables_));
2493
+ };
2494
+
2495
+ streamInfo.getUris = getUris;
2496
+
2469
2497
  /** @param {!shaka.net.NetworkingEngine.PendingRequest} pendingRequest */
2470
2498
  const downloadSegmentIndex = async (pendingRequest) => {
2471
2499
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
2472
2500
 
2473
2501
  try {
2474
- const uris = streamInfo.getUris();
2475
2502
  // Download the actual manifest.
2476
2503
  const response = await pendingRequest.promise;
2477
2504
  if (pendingRequest.aborted) {
@@ -2480,9 +2507,11 @@ shaka.hls.HlsParser = class {
2480
2507
 
2481
2508
  // Record the final URI after redirects.
2482
2509
  const responseUri = response.uri;
2483
- if (responseUri != response.originalUri &&
2484
- !uris.includes(responseUri)) {
2485
- redirectUris.push(responseUri);
2510
+ if (responseUri != response.originalUri) {
2511
+ const uris = streamInfo.getUris();
2512
+ if (!uris.includes(responseUri)) {
2513
+ streamInfo.redirectUris.push(responseUri);
2514
+ }
2486
2515
  }
2487
2516
 
2488
2517
  // Record the redirected, final URI of this media playlist when we parse
@@ -3233,7 +3262,7 @@ shaka.hls.HlsParser = class {
3233
3262
  drmTag, mimeType, getUris, initSegmentRef, variables);
3234
3263
  } else {
3235
3264
  const drmParser =
3236
- shaka.hls.HlsParser.KEYFORMATS_TO_DRM_PARSERS_[keyFormat];
3265
+ shaka.hls.HlsParser.KEYFORMATS_TO_DRM_PARSERS_.get(keyFormat);
3237
3266
  drmInfo = drmParser ? drmParser(drmTag, mimeType) : null;
3238
3267
  }
3239
3268
  if (drmInfo) {
@@ -3657,10 +3686,10 @@ shaka.hls.HlsParser = class {
3657
3686
  const getMimeType = (uri) => {
3658
3687
  const parsedUri = new goog.Uri(uri);
3659
3688
  const extension = parsedUri.getPath().split('.').pop();
3660
- const map = HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_[type];
3661
- let mimeType = map[extension];
3689
+ const map = HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_.get(type);
3690
+ let mimeType = map.get(extension);
3662
3691
  if (!mimeType) {
3663
- mimeType = HlsParser.RAW_FORMATS_TO_MIME_TYPES_[extension];
3692
+ mimeType = HlsParser.RAW_FORMATS_TO_MIME_TYPES_.get(extension);
3664
3693
  }
3665
3694
  return mimeType;
3666
3695
  };
@@ -4434,8 +4463,9 @@ shaka.hls.HlsParser = class {
4434
4463
  }
4435
4464
  // If the HLS content is lacking in both MIME type metadata and
4436
4465
  // segment file extensions, we fall back to assuming it's MP4.
4437
- const map = shaka.hls.HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_[contentType];
4438
- return map['mp4'];
4466
+ const map =
4467
+ shaka.hls.HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_.get(contentType);
4468
+ return map.get('mp4');
4439
4469
  }
4440
4470
 
4441
4471
  /**
@@ -4483,14 +4513,14 @@ shaka.hls.HlsParser = class {
4483
4513
 
4484
4514
  const parsedUri = new goog.Uri(segmentUris[0]);
4485
4515
  const extension = parsedUri.getPath().split('.').pop();
4486
- const map = HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_[contentType];
4516
+ const map = HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_.get(contentType);
4487
4517
 
4488
- let mimeType = map[extension];
4518
+ let mimeType = map.get(extension);
4489
4519
  if (mimeType) {
4490
4520
  return mimeType;
4491
4521
  }
4492
4522
 
4493
- mimeType = HlsParser.RAW_FORMATS_TO_MIME_TYPES_[extension];
4523
+ mimeType = HlsParser.RAW_FORMATS_TO_MIME_TYPES_.get(extension);
4494
4524
  if (mimeType) {
4495
4525
  return mimeType;
4496
4526
  }
@@ -4763,7 +4793,7 @@ shaka.hls.HlsParser = class {
4763
4793
  shaka.util.Error.Code.HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED);
4764
4794
  }
4765
4795
 
4766
- if (shaka.util.Platform.isMediaKeysPolyfilled()) {
4796
+ if (shaka.util.Platform.isMediaKeysPolyfilled('apple')) {
4767
4797
  throw new shaka.util.Error(
4768
4798
  shaka.util.Error.Severity.CRITICAL,
4769
4799
  shaka.util.Error.Category.MANIFEST,
@@ -4953,7 +4983,7 @@ shaka.hls.HlsParser = class {
4953
4983
  shaka.util.Error.Code.HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED);
4954
4984
  }
4955
4985
 
4956
- if (shaka.util.Platform.isMediaKeysPolyfilled()) {
4986
+ if (shaka.util.Platform.isMediaKeysPolyfilled('apple')) {
4957
4987
  throw new shaka.util.Error(
4958
4988
  shaka.util.Error.Severity.CRITICAL,
4959
4989
  shaka.util.Error.Category.MANIFEST,
@@ -5112,91 +5142,85 @@ shaka.hls.HlsParser.StreamInfos;
5112
5142
 
5113
5143
 
5114
5144
  /**
5115
- * @const {!Object<string, string>}
5145
+ * @const {!Map<string, string>}
5116
5146
  * @private
5117
5147
  */
5118
- shaka.hls.HlsParser.RAW_FORMATS_TO_MIME_TYPES_ = {
5119
- 'aac': 'audio/aac',
5120
- 'ac3': 'audio/ac3',
5121
- 'ec3': 'audio/ec3',
5122
- 'mp3': 'audio/mpeg',
5123
- };
5148
+ shaka.hls.HlsParser.RAW_FORMATS_TO_MIME_TYPES_ = new Map()
5149
+ .set('aac', 'audio/aac')
5150
+ .set('ac3', 'audio/ac3')
5151
+ .set('ec3', 'audio/ec3')
5152
+ .set('mp3', 'audio/mpeg');
5124
5153
 
5125
5154
 
5126
5155
  /**
5127
- * @const {!Object<string, string>}
5156
+ * @const {!Map<string, string>}
5128
5157
  * @private
5129
5158
  */
5130
- shaka.hls.HlsParser.AUDIO_EXTENSIONS_TO_MIME_TYPES_ = {
5131
- 'mp4': 'audio/mp4',
5132
- 'mp4a': 'audio/mp4',
5133
- 'm4s': 'audio/mp4',
5134
- 'm4i': 'audio/mp4',
5135
- 'm4a': 'audio/mp4',
5136
- 'm4f': 'audio/mp4',
5137
- 'cmfa': 'audio/mp4',
5138
- // MPEG2-TS also uses video/ for audio: https://bit.ly/TsMse
5139
- 'ts': 'video/mp2t',
5140
- 'tsa': 'video/mp2t',
5141
- };
5159
+ shaka.hls.HlsParser.AUDIO_EXTENSIONS_TO_MIME_TYPES_ = new Map()
5160
+ .set('mp4', 'audio/mp4')
5161
+ .set('mp4a', 'audio/mp4')
5162
+ .set('m4s', 'audio/mp4')
5163
+ .set('m4i', 'audio/mp4')
5164
+ .set('m4a', 'audio/mp4')
5165
+ .set('m4f', 'audio/mp4')
5166
+ .set('cmfa', 'audio/mp4')
5167
+ // MPEG2-TS also uses video/ for audio: https://bit.ly/TsMse
5168
+ .set('ts', 'video/mp2t')
5169
+ .set('tsa', 'video/mp2t');
5142
5170
 
5143
5171
 
5144
5172
  /**
5145
- * @const {!Object<string, string>}
5173
+ * @const {!Map<string, string>}
5146
5174
  * @private
5147
5175
  */
5148
- shaka.hls.HlsParser.VIDEO_EXTENSIONS_TO_MIME_TYPES_ = {
5149
- 'mp4': 'video/mp4',
5150
- 'mp4v': 'video/mp4',
5151
- 'm4s': 'video/mp4',
5152
- 'm4i': 'video/mp4',
5153
- 'm4v': 'video/mp4',
5154
- 'm4f': 'video/mp4',
5155
- 'cmfv': 'video/mp4',
5156
- 'ts': 'video/mp2t',
5157
- 'tsv': 'video/mp2t',
5158
- };
5176
+ shaka.hls.HlsParser.VIDEO_EXTENSIONS_TO_MIME_TYPES_ = new Map()
5177
+ .set('mp4', 'video/mp4')
5178
+ .set('mp4v', 'video/mp4')
5179
+ .set('m4s', 'video/mp4')
5180
+ .set('m4i', 'video/mp4')
5181
+ .set('m4v', 'video/mp4')
5182
+ .set('m4f', 'video/mp4')
5183
+ .set('cmfv', 'video/mp4')
5184
+ .set('ts', 'video/mp2t')
5185
+ .set('tsv', 'video/mp2t');
5159
5186
 
5160
5187
 
5161
5188
  /**
5162
- * @const {!Object<string, string>}
5189
+ * @const {!Map<string, string>}
5163
5190
  * @private
5164
5191
  */
5165
- shaka.hls.HlsParser.TEXT_EXTENSIONS_TO_MIME_TYPES_ = {
5166
- 'mp4': 'application/mp4',
5167
- 'm4s': 'application/mp4',
5168
- 'm4i': 'application/mp4',
5169
- 'm4f': 'application/mp4',
5170
- 'cmft': 'application/mp4',
5171
- 'vtt': 'text/vtt',
5172
- 'webvtt': 'text/vtt',
5173
- 'ttml': 'application/ttml+xml',
5174
- };
5192
+ shaka.hls.HlsParser.TEXT_EXTENSIONS_TO_MIME_TYPES_ = new Map()
5193
+ .set('mp4', 'application/mp4')
5194
+ .set('m4s', 'application/mp4')
5195
+ .set('m4i', 'application/mp4')
5196
+ .set('m4f', 'application/mp4')
5197
+ .set('cmft', 'application/mp4')
5198
+ .set('vtt', 'text/vtt')
5199
+ .set('webvtt', 'text/vtt')
5200
+ .set('ttml', 'application/ttml+xml');
5175
5201
 
5176
5202
 
5177
5203
  /**
5178
- * @const {!Object<string, string>}
5204
+ * @const {!Map<string, string>}
5179
5205
  * @private
5180
5206
  */
5181
- shaka.hls.HlsParser.IMAGE_EXTENSIONS_TO_MIME_TYPES_ = {
5182
- 'jpg': 'image/jpeg',
5183
- 'png': 'image/png',
5184
- 'svg': 'image/svg+xml',
5185
- 'webp': 'image/webp',
5186
- 'avif': 'image/avif',
5187
- };
5207
+ shaka.hls.HlsParser.IMAGE_EXTENSIONS_TO_MIME_TYPES_ = new Map()
5208
+ .set('jpg', 'image/jpeg')
5209
+ .set('png', 'image/png')
5210
+ .set('svg', 'image/svg+xml')
5211
+ .set('webp', 'image/webp')
5212
+ .set('avif', 'image/avif');
5188
5213
 
5189
5214
 
5190
5215
  /**
5191
- * @const {!Object<string, !Object<string, string>>}
5216
+ * @const {!Map<string, !Map<string, string>>}
5192
5217
  * @private
5193
5218
  */
5194
- shaka.hls.HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_ = {
5195
- 'audio': shaka.hls.HlsParser.AUDIO_EXTENSIONS_TO_MIME_TYPES_,
5196
- 'video': shaka.hls.HlsParser.VIDEO_EXTENSIONS_TO_MIME_TYPES_,
5197
- 'text': shaka.hls.HlsParser.TEXT_EXTENSIONS_TO_MIME_TYPES_,
5198
- 'image': shaka.hls.HlsParser.IMAGE_EXTENSIONS_TO_MIME_TYPES_,
5199
- };
5219
+ shaka.hls.HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_ = new Map()
5220
+ .set('audio', shaka.hls.HlsParser.AUDIO_EXTENSIONS_TO_MIME_TYPES_)
5221
+ .set('video', shaka.hls.HlsParser.VIDEO_EXTENSIONS_TO_MIME_TYPES_)
5222
+ .set('text', shaka.hls.HlsParser.TEXT_EXTENSIONS_TO_MIME_TYPES_)
5223
+ .set('image', shaka.hls.HlsParser.IMAGE_EXTENSIONS_TO_MIME_TYPES_);
5200
5224
 
5201
5225
 
5202
5226
  /**
@@ -5220,19 +5244,18 @@ shaka.hls.HlsParser.DrmParser_;
5220
5244
 
5221
5245
 
5222
5246
  /**
5223
- * @const {!Object<string, shaka.hls.HlsParser.DrmParser_>}
5247
+ * @const {!Map<string, shaka.hls.HlsParser.DrmParser_>}
5224
5248
  * @private
5225
5249
  */
5226
- shaka.hls.HlsParser.KEYFORMATS_TO_DRM_PARSERS_ = {
5227
- 'com.apple.streamingkeydelivery':
5228
- shaka.hls.HlsParser.fairplayDrmParser_,
5229
- 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed':
5230
- shaka.hls.HlsParser.widevineDrmParser_,
5231
- 'com.microsoft.playready':
5232
- shaka.hls.HlsParser.playreadyDrmParser_,
5233
- 'urn:uuid:3d5e6d35-9b9a-41e8-b843-dd3c6e72c42c':
5234
- shaka.hls.HlsParser.wiseplayDrmParser_,
5235
- };
5250
+ shaka.hls.HlsParser.KEYFORMATS_TO_DRM_PARSERS_ = new Map()
5251
+ .set('com.apple.streamingkeydelivery',
5252
+ shaka.hls.HlsParser.fairplayDrmParser_)
5253
+ .set('urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed',
5254
+ shaka.hls.HlsParser.widevineDrmParser_)
5255
+ .set('com.microsoft.playready',
5256
+ shaka.hls.HlsParser.playreadyDrmParser_)
5257
+ .set('urn:uuid:3d5e6d35-9b9a-41e8-b843-dd3c6e72c42c',
5258
+ shaka.hls.HlsParser.wiseplayDrmParser_);
5236
5259
 
5237
5260
 
5238
5261
  /**
@@ -143,7 +143,7 @@ shaka.media.ClosedCaptionParser = class {
143
143
  * @export
144
144
  */
145
145
  static registerParser(mimeType, plugin) {
146
- shaka.media.ClosedCaptionParser.parserMap_[mimeType] = plugin;
146
+ shaka.media.ClosedCaptionParser.parserMap_.set(mimeType, plugin);
147
147
  }
148
148
 
149
149
  /**
@@ -151,7 +151,7 @@ shaka.media.ClosedCaptionParser = class {
151
151
  * @export
152
152
  */
153
153
  static unregisterParser(mimeType) {
154
- delete shaka.media.ClosedCaptionParser.parserMap_[mimeType];
154
+ shaka.media.ClosedCaptionParser.parserMap_.delete(mimeType);
155
155
  }
156
156
 
157
157
  /**
@@ -160,7 +160,7 @@ shaka.media.ClosedCaptionParser = class {
160
160
  * @export
161
161
  */
162
162
  static findParser(mimeType) {
163
- return shaka.media.ClosedCaptionParser.parserMap_[mimeType];
163
+ return shaka.media.ClosedCaptionParser.parserMap_.get(mimeType);
164
164
  }
165
165
 
166
166
  /**
@@ -187,8 +187,8 @@ shaka.media.ClosedCaptionParser = class {
187
187
  }
188
188
  };
189
189
 
190
- /** @private {!Object<string, shaka.extern.CeaParserPlugin>} */
191
- shaka.media.ClosedCaptionParser.parserMap_ = {};
190
+ /** @private {!Map<string, shaka.extern.CeaParserPlugin>} */
191
+ shaka.media.ClosedCaptionParser.parserMap_ = new Map();
192
192
 
193
193
  /** @private {?shaka.extern.CaptionDecoderPlugin} */
194
194
  shaka.media.ClosedCaptionParser.decoderFactory_ = null;