@amazon/vinyl 4.0.0 → 4.0.1-next.20261016220320

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 (76) hide show
  1. package/dist/index.cjs +40 -3
  2. package/dist/index.cjs.map +2 -2
  3. package/dist/index.js +41 -3
  4. package/dist/index.js.map +2 -2
  5. package/dist/test/benchmark.es5.js +5 -4
  6. package/dist/test/benchmark.js +11 -2
  7. package/dist/test/benchmark.js.map +3 -3
  8. package/dist/test/errata/mse-changetype-sequence.html +65 -0
  9. package/dist/test/errata/mse-changetype-sequence.js +179 -0
  10. package/dist/test/index.html +2 -2
  11. package/dist/test/integ.es5.js +287 -276
  12. package/dist/test/integ.js +629 -245
  13. package/dist/test/integ.js.map +4 -4
  14. package/dist/test/styles.css +23 -13
  15. package/dist/types/current/playback/PlaybackControllerImpl.d.ts +12 -0
  16. package/dist/types/current/playback/PlaybackControllerImpl.d.ts.map +1 -1
  17. package/dist/types/current/playback/PlaybackControllerImpl.js +42 -1
  18. package/dist/types/current/streaming/buffering/BufferingController.d.ts.map +1 -1
  19. package/dist/types/current/streaming/buffering/BufferingController.js +9 -2
  20. package/dist/types/current/streaming/buffering/MediaSourceController.d.ts.map +1 -1
  21. package/dist/types/current/streaming/buffering/MediaSourceController.js +4 -2
  22. package/dist/types/current/tsconfig.tsbuildinfo +1 -1
  23. package/dist/types/ts3.7/playback/PlaybackControllerImpl.d.ts +12 -0
  24. package/dist/types/ts4.1/playback/PlaybackControllerImpl.d.ts +12 -0
  25. package/dist/types/ts4.7/playback/PlaybackControllerImpl.d.ts +12 -0
  26. package/dist/unit/types/current/playback/PlaybackControllerImpl.test.js +86 -0
  27. package/dist/unit/types/current/setup.js +6 -5
  28. package/dist/unit/types/current/streaming/SegmentControllerImpl.test.js +44 -1
  29. package/dist/unit/types/current/streaming/buffering/BufferingController.test.js +14 -0
  30. package/dist/unit/types/current/streaming/buffering/MediaSourceController.test.js +13 -0
  31. package/dist/unit/types/current/track/dash/createDashFactories.test.js +15 -5
  32. package/dist/unit/types/current/track/hls/createHlsFactories.test.js +36 -12
  33. package/dist/unit/types/current/tsconfig.tsbuildinfo +1 -1
  34. package/dist/unit/types/current/vinyl/VinylPlayerAdBreaks.test.js +8 -5
  35. package/dist/vinylTestUtil/index.js +92 -60
  36. package/dist/vinylTestUtil/index.js.map +4 -4
  37. package/dist/vinylTestUtil/types/current/media/FrequencyAnalyzer.d.ts +8 -5
  38. package/dist/vinylTestUtil/types/current/media/FrequencyAnalyzer.d.ts.map +1 -1
  39. package/dist/vinylTestUtil/types/current/media/FrequencyAnalyzer.js +23 -29
  40. package/dist/vinylTestUtil/types/current/media/unlockMediaElement.d.ts +10 -1
  41. package/dist/vinylTestUtil/types/current/media/unlockMediaElement.d.ts.map +1 -1
  42. package/dist/vinylTestUtil/types/current/media/unlockMediaElement.js +34 -6
  43. package/dist/vinylTestUtil/types/current/player/createVinylSuite.d.ts.map +1 -1
  44. package/dist/vinylTestUtil/types/current/player/createVinylSuite.js +6 -1
  45. package/dist/vinylTestUtil/types/current/player/mediaRef.d.ts +7 -0
  46. package/dist/vinylTestUtil/types/current/player/mediaRef.d.ts.map +1 -1
  47. package/dist/vinylTestUtil/types/current/player/mediaRef.js +8 -1
  48. package/dist/vinylTestUtil/types/current/tsconfig.tsbuildinfo +1 -1
  49. package/dist/vinylTestUtil/types/current/ui/requireUserInteraction.d.ts +6 -2
  50. package/dist/vinylTestUtil/types/current/ui/requireUserInteraction.d.ts.map +1 -1
  51. package/dist/vinylTestUtil/types/current/ui/requireUserInteraction.js +31 -15
  52. package/dist/vinylTestUtil/types/current/util/playback/expectTrackPlays.d.ts +9 -2
  53. package/dist/vinylTestUtil/types/current/util/playback/expectTrackPlays.d.ts.map +1 -1
  54. package/dist/vinylTestUtil/types/current/util/playback/expectTrackPlays.js +10 -7
  55. package/dist/vinylTestUtil/types/current/util/playback/expectTrackPlaysUntil.d.ts +4 -1
  56. package/dist/vinylTestUtil/types/current/util/playback/expectTrackPlaysUntil.d.ts.map +1 -1
  57. package/dist/vinylTestUtil/types/current/util/playback/expectTrackPlaysUntil.js +3 -2
  58. package/dist/vinylTestUtil/types/ts3.7/media/FrequencyAnalyzer.d.ts +8 -5
  59. package/dist/vinylTestUtil/types/ts3.7/media/unlockMediaElement.d.ts +10 -1
  60. package/dist/vinylTestUtil/types/ts3.7/player/mediaRef.d.ts +7 -0
  61. package/dist/vinylTestUtil/types/ts3.7/ui/requireUserInteraction.d.ts +6 -2
  62. package/dist/vinylTestUtil/types/ts3.7/util/playback/expectTrackPlays.d.ts +9 -2
  63. package/dist/vinylTestUtil/types/ts3.7/util/playback/expectTrackPlaysUntil.d.ts +4 -1
  64. package/dist/vinylTestUtil/types/ts4.1/media/FrequencyAnalyzer.d.ts +8 -5
  65. package/dist/vinylTestUtil/types/ts4.1/media/unlockMediaElement.d.ts +10 -1
  66. package/dist/vinylTestUtil/types/ts4.1/player/mediaRef.d.ts +7 -0
  67. package/dist/vinylTestUtil/types/ts4.1/ui/requireUserInteraction.d.ts +6 -2
  68. package/dist/vinylTestUtil/types/ts4.1/util/playback/expectTrackPlays.d.ts +9 -2
  69. package/dist/vinylTestUtil/types/ts4.1/util/playback/expectTrackPlaysUntil.d.ts +4 -1
  70. package/dist/vinylTestUtil/types/ts4.7/media/FrequencyAnalyzer.d.ts +8 -5
  71. package/dist/vinylTestUtil/types/ts4.7/media/unlockMediaElement.d.ts +10 -1
  72. package/dist/vinylTestUtil/types/ts4.7/player/mediaRef.d.ts +7 -0
  73. package/dist/vinylTestUtil/types/ts4.7/ui/requireUserInteraction.d.ts +6 -2
  74. package/dist/vinylTestUtil/types/ts4.7/util/playback/expectTrackPlays.d.ts +9 -2
  75. package/dist/vinylTestUtil/types/ts4.7/util/playback/expectTrackPlaysUntil.d.ts +4 -1
  76. package/package.json +11 -10
@@ -1135,7 +1135,7 @@
1135
1135
  var uncurryThis = require_function_uncurry_this();
1136
1136
  var hasOwn = require_has_own_property();
1137
1137
  var toIndexedObject = require_to_indexed_object();
1138
- var indexOf = require_array_includes().indexOf;
1138
+ var indexOf2 = require_array_includes().indexOf;
1139
1139
  var hiddenKeys = require_hidden_keys();
1140
1140
  var push = uncurryThis([].push);
1141
1141
  module.exports = function(object2, names) {
@@ -1145,7 +1145,7 @@
1145
1145
  var key;
1146
1146
  for (key in O) !hasOwn(hiddenKeys, key) && hasOwn(O, key) && push(result, key);
1147
1147
  while (names.length > i) if (hasOwn(O, key = names[i++])) {
1148
- ~indexOf(result, key) || push(result, key);
1148
+ ~indexOf2(result, key) || push(result, key);
1149
1149
  }
1150
1150
  return result;
1151
1151
  };
@@ -3860,10 +3860,6 @@
3860
3860
  if (nextTestTimeoutOverridden) nextTestTimeoutOverridden = false;
3861
3861
  });
3862
3862
  }
3863
- function setNextTestTimeout(timeout2) {
3864
- nextTestTimeoutOverridden = true;
3865
- jasmine.DEFAULT_TIMEOUT_INTERVAL = timeout2 * 1e3;
3866
- }
3867
3863
 
3868
3864
  // ../vinyl-util/test/browserTestUtil/expect/expectIterableEquals.ts
3869
3865
  function expectIterableEquals(arr1, arr2) {
@@ -4509,7 +4505,7 @@
4509
4505
  __publicField(this, "onsourceended", null);
4510
4506
  __publicField(this, "onsourceopen", null);
4511
4507
  __publicField(this, "readyState", "closed");
4512
- __publicField(this, "sourceBuffers");
4508
+ __publicField(this, "sourceBuffers", []);
4513
4509
  __publicField(this, "addSourceBuffer", createSpy2("addSourceBuffer"));
4514
4510
  __publicField(this, "clearLiveSeekableRange", createSpy2(
4515
4511
  "clearLiveSeekableRange"
@@ -5598,6 +5594,9 @@
5598
5594
  }
5599
5595
 
5600
5596
  // ../vinyl-util/src/util/collection/array.ts
5597
+ function indexOf(arrayLike, element2) {
5598
+ return Array.prototype.indexOf.call(arrayLike, element2);
5599
+ }
5601
5600
  function map(arrayLike, transform, thisArg) {
5602
5601
  return Array.prototype.map.call(arrayLike, transform, thisArg);
5603
5602
  }
@@ -14016,32 +14015,32 @@ ${this.lastInitStack}` : "";
14016
14015
  }
14017
14016
  function getRepresentationAncestry(representation) {
14018
14017
  const adaptationSet = representation.parent;
14019
- const period = adaptationSet.parent;
14020
- const mpd = period.parent;
14021
- return [mpd, period, adaptationSet, representation];
14018
+ const period2 = adaptationSet.parent;
14019
+ const mpd = period2.parent;
14020
+ return [mpd, period2, adaptationSet, representation];
14022
14021
  }
14023
14022
  function mergeIfAnyDefined(...sources) {
14024
14023
  if (!sources.some((source) => source)) return void 0;
14025
14024
  return merge(...sources);
14026
14025
  }
14027
- function calculatePeriodTimeRange(period) {
14028
- return [calculatePeriodStart(period), calculatePeriodEnd(period)];
14026
+ function calculatePeriodTimeRange(period2) {
14027
+ return [calculatePeriodStart(period2), calculatePeriodEnd(period2)];
14029
14028
  }
14030
- function calculatePeriodStart(period) {
14031
- if (period.start != null) return period.start;
14032
- const mpd = period.parent;
14033
- const periodIndex = mpd.Period.indexOf(period);
14029
+ function calculatePeriodStart(period2) {
14030
+ if (period2.start != null) return period2.start;
14031
+ const mpd = period2.parent;
14032
+ const periodIndex = mpd.Period.indexOf(period2);
14034
14033
  if (periodIndex <= 0) return 0;
14035
14034
  const previous = mpd.Period[periodIndex - 1];
14036
14035
  const previousStart = calculatePeriodStart(previous);
14037
14036
  return previous.duration != null ? previousStart + previous.duration : previousStart;
14038
14037
  }
14039
- function calculatePeriodEnd(period) {
14038
+ function calculatePeriodEnd(period2) {
14040
14039
  var _a3;
14041
- if (period.duration != null)
14042
- return calculatePeriodStart(period) + period.duration;
14043
- const mpd = period.parent;
14044
- const periodIndex = mpd.Period.indexOf(period);
14040
+ if (period2.duration != null)
14041
+ return calculatePeriodStart(period2) + period2.duration;
14042
+ const mpd = period2.parent;
14043
+ const periodIndex = mpd.Period.indexOf(period2);
14045
14044
  if (periodIndex < mpd.Period.length - 1)
14046
14045
  return calculatePeriodStart(mpd.Period[periodIndex + 1]);
14047
14046
  else return (_a3 = mpd.mediaPresentationDuration) != null ? _a3 : null;
@@ -14050,18 +14049,18 @@ ${this.lastInitStack}` : "";
14050
14049
  return periodStart + (sampleTime - presentationTimeOffset) / timescale;
14051
14050
  }
14052
14051
  function getPeriodAtTime(manifest3, time) {
14053
- const index = sortedInsertionIndex(manifest3.MPD.Period, time, (time2, period2) => {
14054
- return time2 - calculatePeriodStart(period2);
14052
+ const index = sortedInsertionIndex(manifest3.MPD.Period, time, (time2, period3) => {
14053
+ return time2 - calculatePeriodStart(period3);
14055
14054
  }) - 1;
14056
14055
  if (index < 0) return null;
14057
- const period = manifest3.MPD.Period[index];
14058
- const periodEnd = calculatePeriodEnd(period);
14059
- return periodEnd != null && time >= periodEnd ? null : period;
14056
+ const period2 = manifest3.MPD.Period[index];
14057
+ const periodEnd = calculatePeriodEnd(period2);
14058
+ return periodEnd != null && time >= periodEnd ? null : period2;
14060
14059
  }
14061
- function flattenRepresentations(period) {
14060
+ function flattenRepresentations(period2) {
14062
14061
  var _a3;
14063
14062
  const out = [];
14064
- (_a3 = period.AdaptationSet) == null ? void 0 : _a3.forEach((adaptationSet) => {
14063
+ (_a3 = period2.AdaptationSet) == null ? void 0 : _a3.forEach((adaptationSet) => {
14065
14064
  var _a4;
14066
14065
  (_a4 = adaptationSet.Representation) == null ? void 0 : _a4.forEach((representation) => {
14067
14066
  out.push(representation);
@@ -14069,8 +14068,8 @@ ${this.lastInitStack}` : "";
14069
14068
  });
14070
14069
  return out;
14071
14070
  }
14072
- function flattenMediaRepresentations(period) {
14073
- return flattenRepresentations(period).filter((representation) => {
14071
+ function flattenMediaRepresentations(period2) {
14072
+ return flattenRepresentations(period2).filter((representation) => {
14074
14073
  const { contentType: contentType2 } = getRepresentationMimeInfo(representation);
14075
14074
  return contentType2 === "audio" || contentType2 === "video";
14076
14075
  });
@@ -14120,9 +14119,9 @@ ${this.lastInitStack}` : "";
14120
14119
  const periods = manifest3.MPD.Period;
14121
14120
  const avails = [];
14122
14121
  const breaks = [];
14123
- for (const period of periods) {
14124
- const periodStart = calculatePeriodStart(period);
14125
- for (const eventStream of (_a3 = period.EventStream) != null ? _a3 : []) {
14122
+ for (const period2 of periods) {
14123
+ const periodStart = calculatePeriodStart(period2);
14124
+ for (const eventStream of (_a3 = period2.EventStream) != null ? _a3 : []) {
14126
14125
  const { schemeIdUri } = eventStream;
14127
14126
  const isScte35 = SCTE35_SCHEMES.has(schemeIdUri);
14128
14127
  const isInsert = schemeIdUri === DashAlternativeMpdScheme.INSERT;
@@ -14302,16 +14301,16 @@ ${this.lastInitStack}` : "";
14302
14301
  var _a3, _b;
14303
14302
  const endTime = duration == null ? Infinity : startTime + duration;
14304
14303
  const ads = [];
14305
- for (const period of periods) {
14306
- const periodStart = calculatePeriodStart(period);
14304
+ for (const period2 of periods) {
14305
+ const periodStart = calculatePeriodStart(period2);
14307
14306
  if (periodStart < startTime - SPAN_EPSILON || periodStart >= endTime - SPAN_EPSILON)
14308
14307
  continue;
14309
14308
  const periodEnd = Math.min(
14310
- (_a3 = calculatePeriodEnd(period)) != null ? _a3 : endTime,
14309
+ (_a3 = calculatePeriodEnd(period2)) != null ? _a3 : endTime,
14311
14310
  endTime
14312
14311
  );
14313
14312
  ads.push({
14314
- id: (_b = period.id) != null ? _b : `${breakId}-${ads.length}`,
14313
+ id: (_b = period2.id) != null ? _b : `${breakId}-${ads.length}`,
14315
14314
  startTime: periodStart,
14316
14315
  duration: Number.isFinite(periodEnd) ? periodEnd - periodStart : null,
14317
14316
  uri: null
@@ -14399,13 +14398,13 @@ ${this.lastInitStack}` : "";
14399
14398
  }
14400
14399
  if (mpd.type !== "list") return single;
14401
14400
  const ads = [];
14402
- for (const period of mpd.Period) {
14403
- const imported = (_b = (_a3 = period.ImportedMPD) == null ? void 0 : _a3._content) == null ? void 0 : _b.trim();
14401
+ for (const period2 of mpd.Period) {
14402
+ const imported = (_b = (_a3 = period2.ImportedMPD) == null ? void 0 : _a3._content) == null ? void 0 : _b.trim();
14404
14403
  if (!imported) continue;
14405
14404
  ads.push({
14406
- id: (_c = period.id) != null ? _c : `${id}-${ads.length}`,
14405
+ id: (_c = period2.id) != null ? _c : `${id}-${ads.length}`,
14407
14406
  startTime,
14408
- duration: (_d = period.duration) != null ? _d : null,
14407
+ duration: (_d = period2.duration) != null ? _d : null,
14409
14408
  uri: resolveUrl(imported, documentUrl)
14410
14409
  });
14411
14410
  }
@@ -17433,6 +17432,8 @@ ${this.lastInitStack}` : "";
17433
17432
  this.initializeMutedEvent();
17434
17433
  this.initializeLoopedEvent();
17435
17434
  this.initializeReadyStateChangeEvent();
17435
+ this.initializeSeekWaitingEvent();
17436
+ this.initializeSeekPlayingEvent();
17436
17437
  }
17437
17438
  /**
17438
17439
  * Re-dispatches the plain DOM events without extra information.
@@ -17457,7 +17458,11 @@ ${this.lastInitStack}` : "";
17457
17458
  "waiting",
17458
17459
  "waitingForKey"
17459
17460
  ]) {
17460
- this.domEvents.on(toLowerCase(key), () => this.dispatch(key, {}));
17461
+ this.domEvents.on(toLowerCase(key), () => {
17462
+ if (key === "waiting" && this._waiting) return;
17463
+ if (key === "playing" && this._playing) return;
17464
+ this.dispatch(key, {});
17465
+ });
17461
17466
  }
17462
17467
  this.domEvents.on("progress", (e) => {
17463
17468
  this.dispatch("progress", { loaded: e.loaded, total: e.total });
@@ -17868,6 +17873,34 @@ ${this.lastInitStack}` : "";
17868
17873
  if (!this.paused && !seekAbort.aborted()) this.startStallDetection();
17869
17874
  }
17870
17875
  }
17876
+ /**
17877
+ * Dispatches `waiting` when a seek while playing targets an unbuffered position and the media element did not.
17878
+ * Safari 27 keeps its readyState while seeking, so it never fires `waiting` for the seek.
17879
+ * @private
17880
+ */
17881
+ initializeSeekWaitingEvent() {
17882
+ const timeoutSlot = this.disposer.add(new TimeoutSlot());
17883
+ this.domEvents.on("seeking", () => {
17884
+ timeoutSlot.set(() => {
17885
+ const media = this.media;
17886
+ if (this._waiting || !media.seeking || media.paused) return;
17887
+ const range = this.buffered.getRangeAt(media.currentTime);
17888
+ if (range && range[1] > media.currentTime) return;
17889
+ this.dispatch("waiting", {});
17890
+ }, 0);
17891
+ });
17892
+ }
17893
+ /**
17894
+ * Dispatches `playing` when a seek while playing completes and the media element did not. A seek ends `playing`,
17895
+ * but WebKit only fires `playing` again if its readyState dropped, which it doesn't for a buffered position.
17896
+ * @private
17897
+ */
17898
+ initializeSeekPlayingEvent() {
17899
+ this.domEvents.on("seeked", () => {
17900
+ if (this._playing || this.media.paused || !this.canPlay) return;
17901
+ this.dispatch("playing", {});
17902
+ });
17903
+ }
17871
17904
  /**
17872
17905
  * Dispatches a readyStateChange event when {@link readyState} changes.
17873
17906
  * @private
@@ -18399,7 +18432,8 @@ ${this.lastInitStack}` : "";
18399
18432
  return;
18400
18433
  }
18401
18434
  this.bufferingQuality = streamingSegment.quality;
18402
- if (this.decoderId !== streamingSegment.quality.decoderId) {
18435
+ const reinitialized = this.decoderId !== streamingSegment.quality.decoderId;
18436
+ if (reinitialized) {
18403
18437
  this.decoderId = null;
18404
18438
  await sourceBufferController.appendInit(
18405
18439
  streamingSegment.initData,
@@ -18411,6 +18445,8 @@ ${this.lastInitStack}` : "";
18411
18445
  await sourceBufferController.setTimestampOffset(
18412
18446
  streamingSegment.timestampOffset
18413
18447
  );
18448
+ } else if (reinitialized) {
18449
+ await sourceBufferController.setTimestampOffset(tail.endTime);
18414
18450
  }
18415
18451
  const maxAppendSize = this.getMaxAppendSize(
18416
18452
  streamingSegment.quality.contentType
@@ -18797,7 +18833,7 @@ ${this.lastInitStack}` : "";
18797
18833
  "removing source buffer from media source",
18798
18834
  mediaSource.readyState
18799
18835
  );
18800
- if (mediaSource.readyState !== "closed") {
18836
+ if (mediaSource.readyState !== "closed" && indexOf(mediaSource.sourceBuffers, sourceBuffer) !== -1) {
18801
18837
  mediaSource.removeSourceBuffer(sourceBuffer);
18802
18838
  }
18803
18839
  this.sourceBuffers.delete(sourceBuffer);
@@ -19816,12 +19852,12 @@ ${this.lastInitStack}` : "";
19816
19852
  (qualities) => qualities,
19817
19853
  1
19818
19854
  );
19819
- const periods = timeline.periods.map((period) => {
19820
- const filtered = period.qualities.filter(
19821
- (q, index) => filter(q.metadata, index, mapMetadataArray(period.qualities))
19855
+ const periods = timeline.periods.map((period2) => {
19856
+ const filtered = period2.qualities.filter(
19857
+ (q, index) => filter(q.metadata, index, mapMetadataArray(period2.qualities))
19822
19858
  );
19823
- assertMediaStreamsRetained(period.qualities, filtered, throwError);
19824
- return __spreadProps(__spreadValues({}, period), { qualities: filtered });
19859
+ assertMediaStreamsRetained(period2.qualities, filtered, throwError);
19860
+ return __spreadProps(__spreadValues({}, period2), { qualities: filtered });
19825
19861
  });
19826
19862
  return __spreadProps(__spreadValues({}, timeline), { periods });
19827
19863
  }
@@ -19832,16 +19868,16 @@ ${this.lastInitStack}` : "";
19832
19868
  1
19833
19869
  );
19834
19870
  const periods = [];
19835
- for (const period of timeline.periods) {
19871
+ for (const period2 of timeline.periods) {
19836
19872
  const filtered = [];
19837
- const metadataArray = mapMetadataArray(period.qualities);
19838
- for (let i = 0; i < period.qualities.length; i++) {
19839
- if (await filter(period.qualities[i].metadata, i, metadataArray)) {
19840
- filtered.push(period.qualities[i]);
19873
+ const metadataArray = mapMetadataArray(period2.qualities);
19874
+ for (let i = 0; i < period2.qualities.length; i++) {
19875
+ if (await filter(period2.qualities[i].metadata, i, metadataArray)) {
19876
+ filtered.push(period2.qualities[i]);
19841
19877
  }
19842
19878
  }
19843
- assertMediaStreamsRetained(period.qualities, filtered, throwError);
19844
- periods.push(__spreadProps(__spreadValues({}, period), { qualities: filtered }));
19879
+ assertMediaStreamsRetained(period2.qualities, filtered, throwError);
19880
+ periods.push(__spreadProps(__spreadValues({}, period2), { qualities: filtered }));
19845
19881
  }
19846
19882
  return __spreadProps(__spreadValues({}, timeline), { periods });
19847
19883
  }
@@ -20125,12 +20161,12 @@ ${this.lastInitStack}` : "";
20125
20161
 
20126
20162
  // src/streaming/MediaTimeline.ts
20127
20163
  function getMediaPeriodAtTime(timeline, time) {
20128
- const index = sortedInsertionIndex(timeline.periods, time, (time2, period2) => {
20129
- return time2 - period2.startTime;
20164
+ const index = sortedInsertionIndex(timeline.periods, time, (time2, period3) => {
20165
+ return time2 - period3.startTime;
20130
20166
  }) - 1;
20131
20167
  if (index < 0) return null;
20132
- const period = timeline.periods[index];
20133
- return time >= period.endTime ? null : period;
20168
+ const period2 = timeline.periods[index];
20169
+ return time >= period2.endTime ? null : period2;
20134
20170
  }
20135
20171
 
20136
20172
  // src/streaming/SegmentDataSlot.ts
@@ -20389,9 +20425,9 @@ ${this.lastInitStack}` : "";
20389
20425
  return this._cachedPeriod;
20390
20426
  }
20391
20427
  const timeline = await this.deps.mediaTimelineTransformed.value;
20392
- const period = getMediaPeriodAtTime(timeline, time);
20393
- if (period) this._cachedPeriod = period;
20394
- return period;
20428
+ const period2 = getMediaPeriodAtTime(timeline, time);
20429
+ if (period2) this._cachedPeriod = period2;
20430
+ return period2;
20395
20431
  }
20396
20432
  /**
20397
20433
  * Configures this segment provider and initiates prefetching.
@@ -20648,9 +20684,9 @@ ${this.lastInitStack}` : "";
20648
20684
  */
20649
20685
  async createSlotForTime(time) {
20650
20686
  var _a3;
20651
- const period = await this.getPeriodAtTime(time);
20652
- if (!period) return null;
20653
- const contentTypeQualities = period.qualities.filter(
20687
+ const period2 = await this.getPeriodAtTime(time);
20688
+ if (!period2) return null;
20689
+ const contentTypeQualities = period2.qualities.filter(
20654
20690
  (q) => q.metadata.contentType === this.contentType
20655
20691
  );
20656
20692
  const playableQualities = contentTypeQualities.filter(
@@ -20800,9 +20836,9 @@ ${this.lastInitStack}` : "";
20800
20836
  const periods = manifest3.MPD.Period;
20801
20837
  const mpdBase = chainBase(baseUrl, manifest3.MPD.BaseURL);
20802
20838
  for (let p = 0; p < periods.length; p++) {
20803
- const period = periods[p];
20804
- const periodBase = chainBase(mpdBase, period.BaseURL);
20805
- const adaptationSets = (_a3 = period.AdaptationSet) != null ? _a3 : [];
20839
+ const period2 = periods[p];
20840
+ const periodBase = chainBase(mpdBase, period2.BaseURL);
20841
+ const adaptationSets = (_a3 = period2.AdaptationSet) != null ? _a3 : [];
20806
20842
  for (const adaptationSet of adaptationSets) {
20807
20843
  if (!isTextAdaptationSet(adaptationSet)) continue;
20808
20844
  const asBase = chainBase(periodBase, adaptationSet.BaseURL);
@@ -22328,9 +22364,9 @@ ${this.lastInitStack}` : "";
22328
22364
  updateQualities() {
22329
22365
  this.withTimeline(this.deps.mediaTimelineTransformed, (timeline) => {
22330
22366
  const time = this.deps.playbackController.currentTime;
22331
- const period = getMediaPeriodAtTime(timeline, time);
22332
- this._cachedPeriod = period;
22333
- const newQualities = period ? period.qualities.map((q) => q.metadata) : null;
22367
+ const period2 = getMediaPeriodAtTime(timeline, time);
22368
+ this._cachedPeriod = period2;
22369
+ const newQualities = period2 ? period2.qualities.map((q) => q.metadata) : null;
22334
22370
  if (!equalDeep(newQualities, this._qualities)) {
22335
22371
  const previous = this._qualities;
22336
22372
  this._qualities = newQualities;
@@ -22356,8 +22392,8 @@ ${this.lastInitStack}` : "";
22356
22392
  updateQualitiesUnfiltered() {
22357
22393
  this.withTimeline(this.deps.mediaTimeline, (timeline) => {
22358
22394
  const time = this.deps.playbackController.currentTime;
22359
- const period = getMediaPeriodAtTime(timeline, time);
22360
- const newQualities = period ? period.qualities.map((q) => q.metadata) : null;
22395
+ const period2 = getMediaPeriodAtTime(timeline, time);
22396
+ const newQualities = period2 ? period2.qualities.map((q) => q.metadata) : null;
22361
22397
  if (!equalDeep(newQualities, this._qualitiesUnfiltered)) {
22362
22398
  const previous = this._qualitiesUnfiltered;
22363
22399
  this._qualitiesUnfiltered = newQualities;
@@ -23050,11 +23086,11 @@ ${this.lastInitStack}` : "";
23050
23086
  // src/track/dash/buildDashMediaTimeline.ts
23051
23087
  function buildDashMediaTimeline(deps, data2) {
23052
23088
  const { manifest: manifest3, baseUrl } = data2;
23053
- const periods = manifest3.MPD.Period.map((period) => {
23089
+ const periods = manifest3.MPD.Period.map((period2) => {
23054
23090
  var _a3;
23055
- const startTime = calculatePeriodStart(period);
23056
- const endTime = (_a3 = calculatePeriodEnd(period)) != null ? _a3 : Infinity;
23057
- const representations = flattenMediaRepresentations(period);
23091
+ const startTime = calculatePeriodStart(period2);
23092
+ const endTime = (_a3 = calculatePeriodEnd(period2)) != null ? _a3 : Infinity;
23093
+ const representations = flattenMediaRepresentations(period2);
23058
23094
  const qualities = representations.map(
23059
23095
  (representation) => {
23060
23096
  const metadata = deps.mediaQualityMetadataResolver(representation);
@@ -23113,9 +23149,9 @@ ${this.lastInitStack}` : "";
23113
23149
  }
23114
23150
  function getContentTypes(deps, manifest3) {
23115
23151
  const contentTypes = /* @__PURE__ */ new Set();
23116
- for (const period of manifest3.MPD.Period) {
23117
- if (!period.AdaptationSet) continue;
23118
- const mediaMetadata = flattenMediaRepresentations(period).map(
23152
+ for (const period2 of manifest3.MPD.Period) {
23153
+ if (!period2.AdaptationSet) continue;
23154
+ const mediaMetadata = flattenMediaRepresentations(period2).map(
23119
23155
  deps.mediaQualityMetadataResolver
23120
23156
  );
23121
23157
  for (const { contentType: contentType2 } of mediaMetadata) {
@@ -23128,9 +23164,9 @@ ${this.lastInitStack}` : "";
23128
23164
  // src/track/dash/manifestTransformUtils.ts
23129
23165
  function manifestIsPlayable(manifest3) {
23130
23166
  return manifest3.MPD.Period.every(
23131
- (period) => {
23167
+ (period2) => {
23132
23168
  var _a3;
23133
- return (_a3 = period.AdaptationSet) == null ? void 0 : _a3.some(
23169
+ return (_a3 = period2.AdaptationSet) == null ? void 0 : _a3.some(
23134
23170
  (adaptationSet) => {
23135
23171
  var _a4;
23136
23172
  return (_a4 = adaptationSet.Representation) == null ? void 0 : _a4.length;
@@ -23141,9 +23177,9 @@ ${this.lastInitStack}` : "";
23141
23177
  }
23142
23178
  function filterDashRepresentations(filter, throwError, manifest3) {
23143
23179
  const result = clone(manifest3);
23144
- for (const period of result.MPD.Period) {
23145
- if (period.AdaptationSet) {
23146
- for (const adaptationSet of period.AdaptationSet) {
23180
+ for (const period2 of result.MPD.Period) {
23181
+ if (period2.AdaptationSet) {
23182
+ for (const adaptationSet of period2.AdaptationSet) {
23147
23183
  if (adaptationSet.Representation) {
23148
23184
  adaptationSet.Representation = adaptationSet.Representation.filter(filter);
23149
23185
  }
@@ -23157,9 +23193,9 @@ ${this.lastInitStack}` : "";
23157
23193
  }
23158
23194
  function filterDashAdaptationSets(filter, throwError, manifest3) {
23159
23195
  const result = clone(manifest3);
23160
- for (const period of result.MPD.Period) {
23161
- if (period.AdaptationSet) {
23162
- period.AdaptationSet = period.AdaptationSet.filter(filter);
23196
+ for (const period2 of result.MPD.Period) {
23197
+ if (period2.AdaptationSet) {
23198
+ period2.AdaptationSet = period2.AdaptationSet.filter(filter);
23163
23199
  }
23164
23200
  }
23165
23201
  if (!manifestIsPlayable(result)) {
@@ -23170,16 +23206,16 @@ ${this.lastInitStack}` : "";
23170
23206
  function sortDashAdaptationSets(comparator, manifest3) {
23171
23207
  var _a3;
23172
23208
  const result = clone(manifest3);
23173
- for (const period of result.MPD.Period) {
23174
- (_a3 = period.AdaptationSet) == null ? void 0 : _a3.sort(comparator);
23209
+ for (const period2 of result.MPD.Period) {
23210
+ (_a3 = period2.AdaptationSet) == null ? void 0 : _a3.sort(comparator);
23175
23211
  }
23176
23212
  return result;
23177
23213
  }
23178
23214
  function sortDashRepresentations(comparator, manifest3) {
23179
23215
  const result = clone(manifest3);
23180
- for (const period of result.MPD.Period) {
23181
- if (period.AdaptationSet) {
23182
- for (const adaptationSet of period.AdaptationSet) {
23216
+ for (const period2 of result.MPD.Period) {
23217
+ if (period2.AdaptationSet) {
23218
+ for (const adaptationSet of period2.AdaptationSet) {
23183
23219
  if (adaptationSet.Representation) {
23184
23220
  adaptationSet.Representation.sort(comparator);
23185
23221
  }
@@ -23241,13 +23277,13 @@ ${this.lastInitStack}` : "";
23241
23277
  ErrorOrigin.MEDIA
23242
23278
  );
23243
23279
  const adaptationSet = representation.parent;
23244
- const period = adaptationSet.parent;
23245
- const mpd = period.parent;
23246
- const periodId = (_a3 = period.id) != null ? _a3 : `$${mpd.Period.indexOf(period)}`;
23247
- const adaptationSetId = (_b = adaptationSet.id) != null ? _b : `$${period.AdaptationSet.indexOf(adaptationSet)}`;
23280
+ const period2 = adaptationSet.parent;
23281
+ const mpd = period2.parent;
23282
+ const periodId = (_a3 = period2.id) != null ? _a3 : `$${mpd.Period.indexOf(period2)}`;
23283
+ const adaptationSetId = (_b = adaptationSet.id) != null ? _b : `$${period2.AdaptationSet.indexOf(adaptationSet)}`;
23248
23284
  const qualityId = `${periodId}_${adaptationSetId}_${representation.id}`;
23249
23285
  let decoderId = `${periodId}_${adaptationSetId}`;
23250
- const bitstreamSwitching = (_c = adaptationSet.bitstreamSwitching) != null ? _c : period.bitstreamSwitching;
23286
+ const bitstreamSwitching = (_c = adaptationSet.bitstreamSwitching) != null ? _c : period2.bitstreamSwitching;
23251
23287
  if (!bitstreamSwitching) decoderId += `_${representation.id}`;
23252
23288
  const groupId = `${periodId}_${adaptationSetId}`;
23253
23289
  const switchingGroupIds = resolveAdaptationSetSwitchingGroupIds(
@@ -23326,10 +23362,10 @@ ${this.lastInitStack}` : "";
23326
23362
  return total;
23327
23363
  }
23328
23364
  var getPeriodSortedBandwidths = memoize(
23329
- (period) => {
23365
+ (period2) => {
23330
23366
  var _a3, _b;
23331
23367
  const byType = /* @__PURE__ */ new Map();
23332
- for (const as of (_a3 = period.AdaptationSet) != null ? _a3 : []) {
23368
+ for (const as of (_a3 = period2.AdaptationSet) != null ? _a3 : []) {
23333
23369
  for (const rep of (_b = as.Representation) != null ? _b : []) {
23334
23370
  const contentType2 = getRepresentationMimeInfo(rep).contentType;
23335
23371
  if (!contentType2) continue;
@@ -23348,7 +23384,7 @@ ${this.lastInitStack}` : "";
23348
23384
  }
23349
23385
  return byType;
23350
23386
  },
23351
- (period) => period,
23387
+ (period2) => period2,
23352
23388
  5
23353
23389
  );
23354
23390
  function contentProtectionToMetadata(contentProtection, deps) {
@@ -23441,13 +23477,13 @@ ${this.lastInitStack}` : "";
23441
23477
  }
23442
23478
  function hasRemoteContent(manifest3) {
23443
23479
  var _a3, _b, _c, _d, _e, _f;
23444
- for (const period of manifest3.MPD.Period) {
23445
- if (period.ImportedMPD || period.href || ((_a3 = period.SegmentList) == null ? void 0 : _a3.href))
23480
+ for (const period2 of manifest3.MPD.Period) {
23481
+ if (period2.ImportedMPD || period2.href || ((_a3 = period2.SegmentList) == null ? void 0 : _a3.href))
23446
23482
  return true;
23447
- for (const eventStream of (_b = period.EventStream) != null ? _b : []) {
23483
+ for (const eventStream of (_b = period2.EventStream) != null ? _b : []) {
23448
23484
  if (eventStream.href) return true;
23449
23485
  }
23450
- for (const adaptationSet of (_c = period.AdaptationSet) != null ? _c : []) {
23486
+ for (const adaptationSet of (_c = period2.AdaptationSet) != null ? _c : []) {
23451
23487
  if (adaptationSet.href || ((_d = adaptationSet.SegmentList) == null ? void 0 : _d.href))
23452
23488
  return true;
23453
23489
  for (const representation of (_e = adaptationSet.Representation) != null ? _e : []) {
@@ -23459,10 +23495,10 @@ ${this.lastInitStack}` : "";
23459
23495
  }
23460
23496
  async function resolveLinkedPeriods(fetchText, mpd, baseUrl) {
23461
23497
  const resolved = await Promise.all(
23462
- mpd.Period.map(async (period) => {
23498
+ mpd.Period.map(async (period2) => {
23463
23499
  var _a3;
23464
- const imported = period.ImportedMPD;
23465
- if (!imported) return [period];
23500
+ const imported = period2.ImportedMPD;
23501
+ if (!imported) return [period2];
23466
23502
  const href = (_a3 = imported._content) == null ? void 0 : _a3.trim();
23467
23503
  let importedMpd = null;
23468
23504
  let importedUrl = "";
@@ -23474,15 +23510,15 @@ ${this.lastInitStack}` : "";
23474
23510
  } catch (error) {
23475
23511
  logWarn(
23476
23512
  logTarget4,
23477
- `Linked Period ${period.id} import failed`,
23513
+ `Linked Period ${period2.id} import failed`,
23478
23514
  error
23479
23515
  );
23480
23516
  }
23481
23517
  }
23482
23518
  if (!importedMpd || !isImportableMpd(importedMpd)) {
23483
- return fallbackLinkedPeriod(period);
23519
+ return fallbackLinkedPeriod(period2);
23484
23520
  }
23485
- return [mergeImportedPeriod(mpd, period, importedMpd, importedUrl)];
23521
+ return [mergeImportedPeriod(mpd, period2, importedMpd, importedUrl)];
23486
23522
  })
23487
23523
  );
23488
23524
  mpd.Period = resolved.flat();
@@ -23492,18 +23528,18 @@ ${this.lastInitStack}` : "";
23492
23528
  if (mpd.Period.length !== 1) return false;
23493
23529
  return mpd.availabilityEndTime == null || mpd.availabilityEndTime.getTime() >= Date.now();
23494
23530
  }
23495
- function fallbackLinkedPeriod(period) {
23496
- const regular = period;
23531
+ function fallbackLinkedPeriod(period2) {
23532
+ const regular = period2;
23497
23533
  delete regular.ImportedMPD;
23498
23534
  if (!isValidPeriod(regular)) {
23499
- logWarn(logTarget4, `removing unresolved Linked Period ${period.id}`);
23535
+ logWarn(logTarget4, `removing unresolved Linked Period ${period2.id}`);
23500
23536
  return [];
23501
23537
  }
23502
23538
  return [regular];
23503
23539
  }
23504
- function isValidPeriod(period) {
23540
+ function isValidPeriod(period2) {
23505
23541
  var _a3;
23506
- return !!((_a3 = period.AdaptationSet) == null ? void 0 : _a3.length) || period.duration === 0;
23542
+ return !!((_a3 = period2.AdaptationSet) == null ? void 0 : _a3.length) || period2.duration === 0;
23507
23543
  }
23508
23544
  function mergeImportedPeriod(mpd, linked, importedMpd, importedUrl) {
23509
23545
  var _a3, _b, _c, _d, _e, _f, _g;
@@ -23621,12 +23657,12 @@ ${this.lastInitStack}` : "";
23621
23657
  async function resolveRemoteChildren(fetchText, mpd, baseUrl, depth) {
23622
23658
  const periods = (await Promise.all(
23623
23659
  mpd.Period.map(
23624
- (period) => resolveRemote(fetchText, PERIOD, period, baseUrl, depth)
23660
+ (period2) => resolveRemote(fetchText, PERIOD, period2, baseUrl, depth)
23625
23661
  )
23626
23662
  )).flat();
23627
23663
  await Promise.all(
23628
- periods.map(async (period) => {
23629
- const p = period;
23664
+ periods.map(async (period2) => {
23665
+ const p = period2;
23630
23666
  p.parent = mpd;
23631
23667
  if (p.EventStream) {
23632
23668
  p.EventStream = (await Promise.all(
@@ -24986,14 +25022,14 @@ ${this.lastInitStack}` : "";
24986
25022
  }))
24987
25023
  );
24988
25024
  }
24989
- const period = {
25025
+ const period2 = {
24990
25026
  startTime: 0,
24991
25027
  endTime: Infinity,
24992
25028
  qualities
24993
25029
  };
24994
25030
  let cachedDuration = null;
24995
25031
  return {
24996
- periods: [period],
25032
+ periods: [period2],
24997
25033
  minBufferTime: DEFAULT_MIN_BUFFER_TIME,
24998
25034
  getAdBreaks: () => discoverAdsFromManifest(data2),
24999
25035
  async getDuration() {
@@ -26935,9 +26971,10 @@ ${this.lastInitStack}` : "";
26935
26971
  };
26936
26972
 
26937
26973
  // test/vinylTestUtil/player/mediaRef.ts
26974
+ var MEDIA_VOLUME = 1e-4;
26938
26975
  var mediaRef = lazy(() => {
26939
26976
  const media = document.createElement("video");
26940
- media.muted = true;
26977
+ media.volume = MEDIA_VOLUME;
26941
26978
  media.playsInline = true;
26942
26979
  media.disableRemotePlayback = true;
26943
26980
  return media;
@@ -26950,36 +26987,6 @@ ${this.lastInitStack}` : "";
26950
26987
  }
26951
26988
  });
26952
26989
 
26953
- // test/vinylTestUtil/ui/requireUserInteraction.ts
26954
- async function requireUserInteraction() {
26955
- const audioPrompt = document.getElementById("unlockAudioPrompt");
26956
- audioPrompt.style.removeProperty("display");
26957
- const body = document.body;
26958
- body.focus();
26959
- await new Promise((resolve) => {
26960
- const done = () => {
26961
- body.removeEventListener("click", done);
26962
- body.removeEventListener("keypress", done);
26963
- body.removeEventListener("touchend", done);
26964
- return resolve(void 0);
26965
- };
26966
- body.addEventListener("click", done);
26967
- body.addEventListener("keypress", done);
26968
- body.addEventListener("touchend", done);
26969
- });
26970
- audioPrompt.style.display = "none";
26971
- }
26972
-
26973
- // test/vinylTestUtil/media/unlockMediaElement.ts
26974
- async function unlockMediaElement() {
26975
- const media = mediaRef.value;
26976
- media.src = vinylTestAssets.prog.libmp3lame_60s_2ch_16bit_44100Hz_48kbps;
26977
- await media.play().catch(noop);
26978
- media.pause();
26979
- media.removeAttribute("src");
26980
- media.load();
26981
- }
26982
-
26983
26990
  // test/vinylTestUtil/media/FrequencyAnalyzer.ts
26984
26991
  var TIME_ESTIMATE_TOLERANCE = 0.02;
26985
26992
  var defaultFrequencyAnalyzerOptions = {
@@ -27078,6 +27085,7 @@ ${this.lastInitStack}` : "";
27078
27085
  }
27079
27086
  }
27080
27087
  };
27088
+ var ANALYZER_VOLUME = 0.01;
27081
27089
  var _a2;
27082
27090
  var shouldCheckAudio = parseBoolean(
27083
27091
  ((_a2 = getSearchParams().get("checkAudio")) != null ? _a2 : "0").toLowerCase()
@@ -27088,26 +27096,76 @@ ${this.lastInitStack}` : "";
27088
27096
  return (_a3 = frequencyAnalyzer == null ? void 0 : frequencyAnalyzer.assertFrequency()) != null ? _a3 : Promise.resolve();
27089
27097
  }
27090
27098
  function initializeFrequencyAnalyzer() {
27091
- if (shouldCheckAudio) {
27092
- setNextTestTimeout(300);
27093
- beforeAll(async () => {
27094
- const media = mediaRef.value;
27095
- media.crossOrigin = "anonymous";
27096
- media.muted = false;
27097
- media.volume = 0.01;
27098
- await requireUserInteraction();
27099
- const audioContext = getAudioContext();
27100
- await unlockMediaElement();
27101
- if (audioContext) {
27102
- const source = audioContext.createMediaElementSource(
27103
- mediaRef.value
27099
+ if (!shouldCheckAudio) return;
27100
+ beforeAll(() => {
27101
+ const media = mediaRef.value;
27102
+ media.crossOrigin = "anonymous";
27103
+ media.volume = ANALYZER_VOLUME;
27104
+ const audioContext = getAudioContext();
27105
+ if (audioContext) {
27106
+ const source = audioContext.createMediaElementSource(media);
27107
+ frequencyAnalyzer = new FrequencyAnalyzer(audioContext, source);
27108
+ } else {
27109
+ console.warn("AudioContext not supported");
27110
+ }
27111
+ });
27112
+ }
27113
+
27114
+ // test/vinylTestUtil/ui/requireUserInteraction.ts
27115
+ async function requireUserInteraction(onInteraction) {
27116
+ var _a3;
27117
+ const prompt = document.getElementById("unlockAudioPrompt");
27118
+ prompt.style.removeProperty("display");
27119
+ (_a3 = prompt.querySelector("button")) == null ? void 0 : _a3.focus();
27120
+ await new Promise((resolve) => {
27121
+ let handling = false;
27122
+ const handler = (event) => {
27123
+ var _a4;
27124
+ if (handling) return;
27125
+ handling = true;
27126
+ const result = (_a4 = onInteraction == null ? void 0 : onInteraction()) != null ? _a4 : Promise.resolve();
27127
+ result.then(() => {
27128
+ prompt.removeEventListener("click", handler);
27129
+ document.removeEventListener("keydown", handler);
27130
+ resolve();
27131
+ }).catch((error) => {
27132
+ console.warn(
27133
+ `The ${event.type} (isTrusted: ${event.isTrusted}) was not accepted as a user gesture; interact again.`,
27134
+ error
27104
27135
  );
27105
- frequencyAnalyzer = new FrequencyAnalyzer(audioContext, source);
27106
- } else {
27107
- console.warn("AudioContext not supported");
27108
- }
27109
- });
27136
+ }).finally(() => {
27137
+ handling = false;
27138
+ });
27139
+ };
27140
+ prompt.addEventListener("click", handler);
27141
+ document.addEventListener("keydown", handler);
27142
+ });
27143
+ prompt.style.display = "none";
27144
+ }
27145
+
27146
+ // test/vinylTestUtil/media/unlockMediaElement.ts
27147
+ var MAX_TIMEOUT_MS = 2147483647;
27148
+ async function unlockMediaElement() {
27149
+ var _a3;
27150
+ const media = mediaRef.value;
27151
+ media.src = vinylTestAssets.prog.libmp3lame_60s_2ch_16bit_44100Hz_48kbps;
27152
+ const played = media.play();
27153
+ const resumed = (_a3 = getAudioContext()) == null ? void 0 : _a3.resume().catch(noop);
27154
+ try {
27155
+ await played;
27156
+ } finally {
27157
+ media.pause();
27158
+ media.removeAttribute("src");
27159
+ media.load();
27110
27160
  }
27161
+ await resumed;
27162
+ }
27163
+ function initializeMediaUnlock() {
27164
+ if (typeof document === "undefined") return;
27165
+ beforeAll(async () => {
27166
+ await requireUserInteraction(unlockMediaElement);
27167
+ console.info("Media element unlocked");
27168
+ }, MAX_TIMEOUT_MS);
27111
27169
  }
27112
27170
 
27113
27171
  // test/vinylTestUtil/mediaSource/ControlledMediaSource.ts
@@ -27377,6 +27435,8 @@ ${this.lastInitStack}` : "";
27377
27435
  * failedExpectations, save this from `specDone`.
27378
27436
  */
27379
27437
  __publicField(this, "failedResult", null);
27438
+ __publicField(this, "failures", []);
27439
+ __publicField(this, "statusCounts", {});
27380
27440
  __publicField(this, "totalSpecs", 0);
27381
27441
  __publicField(this, "totalCompleted", 0);
27382
27442
  /**
@@ -27407,13 +27467,29 @@ ${this.lastInitStack}` : "";
27407
27467
  this.maybeReportProgress();
27408
27468
  }
27409
27469
  specDone(result) {
27410
- if (!this.failedResult && result.status === "failed")
27411
- this.failedResult = result;
27470
+ var _a3, _b;
27471
+ if (result.status === "failed") {
27472
+ (_a3 = this.failedResult) != null ? _a3 : this.failedResult = result;
27473
+ this.addFailure(result.fullName, result.failedExpectations);
27474
+ }
27475
+ this.statusCounts[result.status] = ((_b = this.statusCounts[result.status]) != null ? _b : 0) + 1;
27412
27476
  this.totalCompleted++;
27413
27477
  this.maybeReportProgress();
27414
27478
  }
27479
+ suiteDone(result) {
27480
+ if (result.failedExpectations.length)
27481
+ this.addFailure(result.fullName, result.failedExpectations);
27482
+ }
27483
+ addFailure(fullName, failedExpectations) {
27484
+ this.failures.push({
27485
+ fullName,
27486
+ messages: failedExpectations.map((e) => e.message)
27487
+ });
27488
+ }
27415
27489
  jasmineDone(runDetails) {
27416
27490
  var _a3;
27491
+ if (runDetails.failedExpectations.length)
27492
+ this.addFailure("top level", runDetails.failedExpectations);
27417
27493
  this.maybeReportProgress(true);
27418
27494
  this.consoleInterceptor.dispose();
27419
27495
  const reason = this.failedResult ? `${this.failedResult.fullName}:
@@ -27423,7 +27499,10 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
27423
27499
  overallStatus: runDetails.overallStatus === "incomplete" ? "passed" : runDetails.overallStatus,
27424
27500
  totalCompleted: this.totalCompleted,
27425
27501
  totalSpecs: this.totalSpecs,
27426
- reason
27502
+ reason,
27503
+ statusCounts: this.statusCounts,
27504
+ failures: this.failures,
27505
+ seed: String(runDetails.order.seed)
27427
27506
  };
27428
27507
  this.onDone(body).catch((_) => {
27429
27508
  this.onDone(body).catch((e) => {
@@ -27583,6 +27662,12 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
27583
27662
 
27584
27663
  // ../vinyl-util/test/testUtil/util/event/createEventSpy.ts
27585
27664
  var createSpy4 = jasmine.createSpy;
27665
+ var pendingTimeouts = /* @__PURE__ */ new Set();
27666
+ if (typeof afterEach === "function")
27667
+ afterEach(() => {
27668
+ for (const abort of pendingTimeouts) abort.abort();
27669
+ pendingTimeouts.clear();
27670
+ });
27586
27671
  function createEventSpy(host, type) {
27587
27672
  const spy = createSpy4(String(type));
27588
27673
  let nextCall = new Deferred();
@@ -27592,12 +27677,29 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
27592
27677
  });
27593
27678
  const unsub = host.on(type, spy);
27594
27679
  return Object.assign(spy, {
27595
- next(timeout2 = 5, timeoutMessage = `event '{type}' has not been dispatched after {timeout}s.`) {
27596
- return withTimeout(nextCall, timeout2, {
27597
- message: substitute(timeoutMessage, {
27598
- type,
27599
- timeout: timeout2
27680
+ next(time = 5, timeoutMessage = `event '{type}' has not been dispatched after {timeout}s.`) {
27681
+ const call = nextCall;
27682
+ const abort = new Abort();
27683
+ pendingTimeouts.add(abort);
27684
+ const settle = () => {
27685
+ abort.abort();
27686
+ pendingTimeouts.delete(abort);
27687
+ };
27688
+ return Promise.race([
27689
+ call,
27690
+ timeout(time, {
27691
+ abort,
27692
+ message: substitute(timeoutMessage, {
27693
+ type,
27694
+ timeout: time
27695
+ })
27600
27696
  })
27697
+ ]).then(() => {
27698
+ settle();
27699
+ return call;
27700
+ }).catch((error) => {
27701
+ settle();
27702
+ throw error;
27601
27703
  });
27602
27704
  },
27603
27705
  dispose: unsub
@@ -28408,6 +28510,7 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
28408
28510
  this.visibilityChangeHandler
28409
28511
  );
28410
28512
  this._player = this.playerFactory();
28513
+ this._player.volume = shouldCheckAudio ? ANALYZER_VOLUME : MEDIA_VOLUME;
28411
28514
  add(
28412
28515
  this._player.on("error", (e) => {
28413
28516
  logError(this, "player emitted error event", toJson(e));
@@ -28558,13 +28661,13 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
28558
28661
  var sleepInterval = 1;
28559
28662
  var affordanceBefore = 1;
28560
28663
  var affordanceAfter = 3;
28561
- async function expectTrackPlaysUntil(player, endTime, timeout2 = 20) {
28664
+ async function expectTrackPlaysUntil(player, endTime, timeout2 = 20, { timeoutScale = 1 } = {}) {
28562
28665
  await onPlaying(player);
28563
28666
  await onTimeUpdate(player);
28564
28667
  const startedBeforeEnd = player.currentTime < endTime;
28565
28668
  await assertFrequency();
28566
28669
  let elapsed = 0;
28567
- const maxTime = endTime - player.currentTime + timeout2;
28670
+ const maxTime = (endTime - player.currentTime + timeout2) * timeoutScale;
28568
28671
  while (!player.ended && player.currentTime < endTime && elapsed < maxTime) {
28569
28672
  await sleep(sleepInterval);
28570
28673
  elapsed += sleepInterval;
@@ -28577,7 +28680,7 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
28577
28680
 
28578
28681
  // test/vinylTestUtil/util/playback/expectTrackPlays.ts
28579
28682
  var PLAYBACK_DURATION = 6;
28580
- async function expectTrackPlays(player) {
28683
+ async function expectTrackPlays(player, { timeoutScale = 1 } = {}) {
28581
28684
  const { dispose, add } = createDisposer();
28582
28685
  const ended = add(createEventSpy(player, "ended"));
28583
28686
  const timeUpdate = add(createEventSpy(player, "timeUpdate"));
@@ -28588,12 +28691,14 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
28588
28691
  if (player.duration > PLAYBACK_DURATION) {
28589
28692
  await expectTrackPlaysUntil(
28590
28693
  player,
28591
- player.currentTime + PLAYBACK_DURATION / 2
28694
+ player.currentTime + PLAYBACK_DURATION / 2,
28695
+ void 0,
28696
+ { timeoutScale }
28592
28697
  );
28593
28698
  const time = player.duration - PLAYBACK_DURATION / 2;
28594
28699
  await player.seekTo(time);
28595
28700
  }
28596
- await ended.next(PLAYBACK_DURATION + 10);
28701
+ await ended.next((PLAYBACK_DURATION + 10) * timeoutScale);
28597
28702
  expect(player.currentTime).toBeCloseToWithin(duration, 3);
28598
28703
  expect(player.ended).withContext("ended").toBeTrue();
28599
28704
  expect(timeUpdate.calls.count()).toBeGreaterThanOrEqual(
@@ -28601,10 +28706,10 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
28601
28706
  );
28602
28707
  dispose();
28603
28708
  }
28604
- async function expectPlaylistPlays(player, playlist) {
28709
+ async function expectPlaylistPlays(player, playlist, { timeoutScale = 1 } = {}) {
28605
28710
  var _a3;
28606
28711
  const { dispose, add } = createDisposer();
28607
- const trackTimeout = PLAYBACK_DURATION + 60;
28712
+ const trackTimeout = (PLAYBACK_DURATION + 60) * timeoutScale;
28608
28713
  const queueEnded = add(createEventSpy(player, "queueEnded"));
28609
28714
  const queueChange = add(createEventSpy(player, "queueChange"));
28610
28715
  const trackChange = add(createEventSpy(player, "trackActivated"));
@@ -28619,8 +28724,10 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
28619
28724
  const isLastTrack = i === playlist.length - 1;
28620
28725
  expect((_a3 = player.activeTrack) == null ? void 0 : _a3.uri).withContext("activeTrack uri").toBe(playlist[i].uri);
28621
28726
  const nextTrack = isLastTrack ? queueEnded.next(trackTimeout) : trackChange.next(trackTimeout);
28622
- await expectTrackPlays(player);
28623
- await nextTrack;
28727
+ await Promise.all([
28728
+ expectTrackPlays(player, { timeoutScale }),
28729
+ nextTrack
28730
+ ]);
28624
28731
  assertQueueChangeCount(isLastTrack ? 0 : 1);
28625
28732
  }
28626
28733
  dispose();
@@ -38970,6 +39077,92 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
38970
39077
  expect(waitedSpy).not.toHaveBeenCalled();
38971
39078
  });
38972
39079
  });
39080
+ describe("when a seek while playing targets an unbuffered position", () => {
39081
+ let waitingSpy;
39082
+ beforeEach(() => {
39083
+ waitingSpy = createSpy12("waiting");
39084
+ controller.on("waiting", waitingSpy);
39085
+ media.buffered = new MockTimeRanges([[0, 20]]);
39086
+ media.currentTime = 22;
39087
+ media.seeking = true;
39088
+ });
39089
+ it("emits waiting if the media element does not", async () => {
39090
+ media.dispatchEvent(mockEvent("seeking"));
39091
+ expect(waitingSpy).not.toHaveBeenCalled();
39092
+ await clock.tick();
39093
+ expect(waitingSpy).toHaveBeenCalledTimes(1);
39094
+ expect(controller.waiting).toBeTrue();
39095
+ media.dispatchEvent(mockEvent("waiting"));
39096
+ expect(waitingSpy).toHaveBeenCalledTimes(1);
39097
+ media.seeking = false;
39098
+ media.dispatchEvent(mockEvent("playing"));
39099
+ expect(controller.waiting).toBeFalse();
39100
+ });
39101
+ it("emits waiting once if the media element does", async () => {
39102
+ media.dispatchEvent(mockEvent("seeking"));
39103
+ media.dispatchEvent(mockEvent("waiting"));
39104
+ await clock.tick();
39105
+ expect(waitingSpy).toHaveBeenCalledTimes(1);
39106
+ });
39107
+ it("does not emit waiting when paused", async () => {
39108
+ media.paused = true;
39109
+ media.dispatchEvent(mockEvent("seeking"));
39110
+ await clock.tick();
39111
+ expect(waitingSpy).not.toHaveBeenCalled();
39112
+ });
39113
+ it("does not emit waiting when the seek completes first", async () => {
39114
+ media.dispatchEvent(mockEvent("seeking"));
39115
+ media.seeking = false;
39116
+ media.dispatchEvent(mockEvent("seeked"));
39117
+ await clock.tick();
39118
+ expect(waitingSpy).not.toHaveBeenCalled();
39119
+ });
39120
+ });
39121
+ describe("when a seek while playing completes", () => {
39122
+ let playingSpy;
39123
+ beforeEach(() => {
39124
+ media.readyState = 4 /* HAVE_ENOUGH_DATA */;
39125
+ media.dispatchEvent(mockEvent("playing"));
39126
+ playingSpy = createSpy12("playing");
39127
+ controller.on("playing", playingSpy);
39128
+ media.dispatchEvent(mockEvent("seeking"));
39129
+ expect(controller.playing).toBeFalse();
39130
+ });
39131
+ it("emits playing if the media element does not", () => {
39132
+ media.dispatchEvent(mockEvent("seeked"));
39133
+ expect(playingSpy).toHaveBeenCalledTimes(1);
39134
+ expect(controller.playing).toBeTrue();
39135
+ media.dispatchEvent(mockEvent("playing"));
39136
+ expect(playingSpy).toHaveBeenCalledTimes(1);
39137
+ });
39138
+ it("emits playing once if the media element does", () => {
39139
+ media.dispatchEvent(mockEvent("playing"));
39140
+ media.dispatchEvent(mockEvent("seeked"));
39141
+ expect(playingSpy).toHaveBeenCalledTimes(1);
39142
+ });
39143
+ it("does not emit playing when paused", () => {
39144
+ media.paused = true;
39145
+ media.dispatchEvent(mockEvent("seeked"));
39146
+ expect(playingSpy).not.toHaveBeenCalled();
39147
+ });
39148
+ it("does not emit playing without future data", () => {
39149
+ media.readyState = 2 /* HAVE_CURRENT_DATA */;
39150
+ media.dispatchEvent(mockEvent("seeked"));
39151
+ expect(playingSpy).not.toHaveBeenCalled();
39152
+ });
39153
+ });
39154
+ describe("when a seek while playing targets a buffered position", () => {
39155
+ it("does not emit waiting", async () => {
39156
+ const waitingSpy = createSpy12("waiting");
39157
+ controller.on("waiting", waitingSpy);
39158
+ media.buffered = new MockTimeRanges([[0, 30]]);
39159
+ media.currentTime = 22;
39160
+ media.seeking = true;
39161
+ media.dispatchEvent(mockEvent("seeking"));
39162
+ await clock.tick();
39163
+ expect(waitingSpy).not.toHaveBeenCalled();
39164
+ });
39165
+ });
38973
39166
  });
38974
39167
  describe("pause", () => {
38975
39168
  it("invokes pause on the element", () => {
@@ -39176,12 +39369,13 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
39176
39369
  addCustomMatchers();
39177
39370
  setGlobalRefDebug(true);
39178
39371
  jasmine.getEnv().configure({
39179
- stopOnSpecFailure: true,
39372
+ stopOnSpecFailure: getSearchParams().get("stopOnSpecFailure") !== "false",
39180
39373
  stopSpecOnExpectationFailure: true,
39181
39374
  failSpecWithNoExpectations: true
39182
39375
  });
39183
39376
  jasmine.getEnv().addReporter(new ConsoleReporter());
39184
39377
  RestApiReporter.installFromSearchParam();
39378
+ initializeMediaUnlock();
39185
39379
  initializeFrequencyAnalyzer();
39186
39380
  afterEach(async () => {
39187
39381
  await flushPromises();
@@ -40410,6 +40604,22 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
40410
40604
  "opus"
40411
40605
  );
40412
40606
  });
40607
+ it("continues after the buffered segment once the new initialization segment is appended", async () => {
40608
+ await open();
40609
+ sourceBufferController.setTimestampOffset.calls.reset();
40610
+ segmentController.getSegment.and.callFake((time) => {
40611
+ const mockSegment = createMockSegment(time);
40612
+ if (mockSegment.startTime >= 10) {
40613
+ mockSegment.quality.decoderId = "next period";
40614
+ mockSegment.timestampOffset = mockSegment.startTime - 4;
40615
+ }
40616
+ return Promise.resolve(mockSegment);
40617
+ });
40618
+ await setTime(9);
40619
+ expect(
40620
+ sourceBufferController.setTimestampOffset
40621
+ ).toHaveBeenCalledOnceWith(10);
40622
+ });
40413
40623
  });
40414
40624
  describe("when segment controller returns null", () => {
40415
40625
  beforeEach(() => {
@@ -41199,6 +41409,11 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
41199
41409
  ).toThrowError(MediaSourceError, "error creating source buffer");
41200
41410
  });
41201
41411
  describe("SourceBufferRef disposal", () => {
41412
+ beforeEach(() => {
41413
+ mockMediaSource.sourceBuffers = [
41414
+ mockSourceBuffer
41415
+ ];
41416
+ });
41202
41417
  it("removes source buffer from media source", () => {
41203
41418
  mockMediaSource.readyState = "open";
41204
41419
  const ref = controller.createSourceBuffer("audio", "audio/mp4");
@@ -41216,6 +41431,15 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
41216
41431
  mockMediaSource.removeSourceBuffer
41217
41432
  ).not.toHaveBeenCalled();
41218
41433
  });
41434
+ it("does not remove a source buffer the media source already removed", () => {
41435
+ mockMediaSource.readyState = "open";
41436
+ const ref = controller.createSourceBuffer("audio", "audio/mp4");
41437
+ mockMediaSource.sourceBuffers = [];
41438
+ ref.dispose();
41439
+ expect(
41440
+ mockMediaSource.removeSourceBuffer
41441
+ ).not.toHaveBeenCalled();
41442
+ });
41219
41443
  });
41220
41444
  });
41221
41445
  describe("endOfStream", () => {
@@ -44783,6 +45007,51 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
44783
45007
  });
44784
45008
  expect(await segmentController.getSegment(5)).toBeNull();
44785
45009
  });
45010
+ describe("when a codec has been denylisted", () => {
45011
+ const OPUS = 'audio/mp4; codecs="opus"';
45012
+ const AAC = 'audio/mp4; codecs="mp4a.40.2"';
45013
+ let selectQuality;
45014
+ beforeEach(() => {
45015
+ timelineData.value = Promise.resolve({
45016
+ periods: [
45017
+ {
45018
+ startTime: 0,
45019
+ endTime: 100,
45020
+ qualities: [OPUS, AAC].map((mimeType, i) => ({
45021
+ metadata: __spreadProps(__spreadValues({}, createEmptyMediaQualityMetadata()), {
45022
+ contentType: "audio",
45023
+ mimeType,
45024
+ decoderId: String(i)
45025
+ }),
45026
+ getSegment: (time) => segmentProvider.getSegment(time)
45027
+ }))
45028
+ }
45029
+ ],
45030
+ minBufferTime: 10,
45031
+ getAdBreaks: () => Promise.resolve([]),
45032
+ getDuration: () => Promise.resolve(100)
45033
+ });
45034
+ selectQuality = spyOn(
45035
+ mockDeps.qualitySelector,
45036
+ "selectQuality"
45037
+ ).and.returnValue(0);
45038
+ });
45039
+ afterEach(() => clearCodecDenylist());
45040
+ function selectedFrom() {
45041
+ return selectQuality.calls.mostRecent().args[0].map((metadata) => metadata.mimeType);
45042
+ }
45043
+ it("selects only from qualities whose codecs are not denylisted", async () => {
45044
+ denylistCodecsFromMimeType(OPUS);
45045
+ await segmentController.getSegment(5);
45046
+ expect(selectedFrom()).toEqual([AAC]);
45047
+ });
45048
+ it("selects from every quality if all of their codecs are denylisted", async () => {
45049
+ denylistCodecsFromMimeType(OPUS);
45050
+ denylistCodecsFromMimeType(AAC);
45051
+ await segmentController.getSegment(5);
45052
+ expect(selectedFrom()).toEqual([OPUS, AAC]);
45053
+ });
45054
+ });
44786
45055
  it("returns null when quality getSegment returns null within period", async () => {
44787
45056
  await fillPrefetch();
44788
45057
  segmentController.clear();
@@ -49195,7 +49464,8 @@ x`);
49195
49464
  type: "dash",
49196
49465
  manifestProvider
49197
49466
  });
49198
- const deps = createContainer(factories).dependencies;
49467
+ const container = createContainer(factories);
49468
+ const deps = container.dependencies;
49199
49469
  expect(deps).toEqual(
49200
49470
  objectContaining16({
49201
49471
  baseUrlSelector: pickFirstBaseUrlSelector,
@@ -49210,6 +49480,7 @@ x`);
49210
49480
  qualitySelector: any22(QualitySelectorImpl)
49211
49481
  })
49212
49482
  );
49483
+ container.dispose();
49213
49484
  });
49214
49485
  it("wires per-track option observables from the player options", () => {
49215
49486
  const factoryCreator = createDashFactories(null);
@@ -49218,11 +49489,13 @@ x`);
49218
49489
  type: "dash",
49219
49490
  manifestProvider
49220
49491
  });
49221
- const deps = createContainer(factories).dependencies;
49492
+ const container = createContainer(factories);
49493
+ const deps = container.dependencies;
49222
49494
  const options2 = dashFactoryDeps.options.value;
49223
49495
  expect(deps.audio.value).toBe(options2.audio);
49224
49496
  expect(deps.allowedContentTypes.value).toBe(options2.allowedContentTypes);
49225
49497
  expect(deps.abr.value).toBe(options2.abr);
49498
+ container.dispose();
49226
49499
  });
49227
49500
  it("provides streaming options to createContentStreamFactories", () => {
49228
49501
  const factoryCreator = createDashFactories({
@@ -49237,8 +49510,10 @@ x`);
49237
49510
  type: "dash",
49238
49511
  manifestProvider
49239
49512
  });
49240
- const deps = createContainer(factories).dependencies;
49513
+ const container = createContainer(factories);
49514
+ const deps = container.dependencies;
49241
49515
  expect(deps.contentStreamFactory("audio")).toEqual(any22(Object));
49516
+ container.dispose();
49242
49517
  });
49243
49518
  it("creates a sidecar text track controller and populates from manifest", async () => {
49244
49519
  const factoryCreator = createDashFactories(null);
@@ -49267,12 +49542,14 @@ x`);
49267
49542
  type: "dash",
49268
49543
  manifestProvider: provider
49269
49544
  });
49270
- const deps = createContainer(factories).dependencies;
49545
+ const container = createContainer(factories);
49546
+ const deps = container.dependencies;
49271
49547
  const ttc = deps.textTrackController;
49272
49548
  await deps.manifestTransformed.value;
49273
49549
  await new Promise((r) => setTimeout(r, 0));
49274
49550
  expect(ttc).toBeDefined();
49275
49551
  expect(ttc.textTracks.length).toBeGreaterThan(0);
49552
+ container.dispose();
49276
49553
  });
49277
49554
  it("text track controller swallows manifest fetch errors", async () => {
49278
49555
  const factoryCreator = createDashFactories(null);
@@ -49284,11 +49561,13 @@ x`);
49284
49561
  type: "dash",
49285
49562
  manifestProvider: provider
49286
49563
  });
49287
- const deps = createContainer(factories).dependencies;
49564
+ const container = createContainer(factories);
49565
+ const deps = container.dependencies;
49288
49566
  const controller = deps.textTrackController;
49289
49567
  await deps.manifestTransformed.value.catch(() => void 0);
49290
49568
  await new Promise((r) => setTimeout(r, 0));
49291
49569
  expect(controller.textTracks).toEqual([]);
49570
+ container.dispose();
49292
49571
  });
49293
49572
  });
49294
49573
 
@@ -49364,9 +49643,9 @@ x`);
49364
49643
  it("sorts adaptation sets by descending selectionPriority", async () => {
49365
49644
  const result = await transform(clone(mockManifest));
49366
49645
  const selectionPriorities = result.manifest.MPD.Period.map(
49367
- (period) => {
49646
+ (period2) => {
49368
49647
  var _a3;
49369
- return ((_a3 = period.AdaptationSet) != null ? _a3 : []).map((as) => as.selectionPriority);
49648
+ return ((_a3 = period2.AdaptationSet) != null ? _a3 : []).map((as) => as.selectionPriority);
49370
49649
  }
49371
49650
  );
49372
49651
  expect(selectionPriorities).toEqual([[3, 2, 1]]);
@@ -49374,9 +49653,9 @@ x`);
49374
49653
  it("sorts representations by ascending qualityRanking", async () => {
49375
49654
  const result = await transform(clone(mockManifest));
49376
49655
  const qualityRanks = result.manifest.MPD.Period.map(
49377
- (period) => {
49656
+ (period2) => {
49378
49657
  var _a3;
49379
- return ((_a3 = period.AdaptationSet) != null ? _a3 : []).map(
49658
+ return ((_a3 = period2.AdaptationSet) != null ? _a3 : []).map(
49380
49659
  (as) => {
49381
49660
  var _a4;
49382
49661
  return ((_a4 = as.Representation) != null ? _a4 : []).map((r) => r.qualityRanking);
@@ -50410,10 +50689,10 @@ x`);
50410
50689
  expect(mockRequester.request).not.toHaveBeenCalled();
50411
50690
  });
50412
50691
  describe("Linked Periods", () => {
50413
- function imported(period, attributes = "") {
50692
+ function imported(period2, attributes = "") {
50414
50693
  return mpd(
50415
50694
  `<BaseURL>media/</BaseURL>
50416
- ${period}`,
50695
+ ${period2}`,
50417
50696
  attributes
50418
50697
  );
50419
50698
  }
@@ -50607,18 +50886,18 @@ x`);
50607
50886
  </AdaptationSet>
50608
50887
  </Period>`)
50609
50888
  );
50610
- const [period] = manifest3.MPD.Period;
50611
- expect((_b = (_a3 = period.SegmentList) == null ? void 0 : _a3.SegmentURL) == null ? void 0 : _b[0].media).toBe("s1.m4s");
50612
- expect((_c = period.EventStream) == null ? void 0 : _c.map((e) => e.schemeIdUri)).toEqual([
50889
+ const [period2] = manifest3.MPD.Period;
50890
+ expect((_b = (_a3 = period2.SegmentList) == null ? void 0 : _a3.SegmentURL) == null ? void 0 : _b[0].media).toBe("s1.m4s");
50891
+ expect((_c = period2.EventStream) == null ? void 0 : _c.map((e) => e.schemeIdUri)).toEqual([
50613
50892
  "urn:remote"
50614
50893
  ]);
50615
- expect((_d = period.AdaptationSet) == null ? void 0 : _d.map((a) => a.id)).toEqual([1, 1, 9]);
50616
- const video = period.AdaptationSet[2];
50894
+ expect((_d = period2.AdaptationSet) == null ? void 0 : _d.map((a) => a.id)).toEqual([1, 1, 9]);
50895
+ const video = period2.AdaptationSet[2];
50617
50896
  expect((_e = video.SegmentList) == null ? void 0 : _e.duration).toBe(2);
50618
50897
  expect((_g = (_f = video.Representation) == null ? void 0 : _f[0].SegmentList) == null ? void 0 : _g.duration).toBe(2);
50619
50898
  expect((_h = video.Representation) == null ? void 0 : _h[0].parent).toBe(video);
50620
50899
  expect((_i = video.Representation) == null ? void 0 : _i[1].SegmentList).toBeUndefined();
50621
- expect((_j = period.AdaptationSet) == null ? void 0 : _j[0].parent).toBe(period);
50900
+ expect((_j = period2.AdaptationSet) == null ? void 0 : _j[0].parent).toBe(period2);
50622
50901
  });
50623
50902
  it("removes elements whose fragment is empty", async () => {
50624
50903
  var _a3;
@@ -50633,10 +50912,10 @@ x`);
50633
50912
  </Period>
50634
50913
  <Period id="zero" duration="PT0S"><ImportedMPD>zero.mpd</ImportedMPD></Period>`)
50635
50914
  );
50636
- const [period, zero] = manifest3.MPD.Period;
50637
- expect(period.SegmentList).toBeUndefined();
50638
- expect(period.EventStream).toEqual([]);
50639
- expect((_a3 = period.AdaptationSet) == null ? void 0 : _a3.length).toBe(1);
50915
+ const [period2, zero] = manifest3.MPD.Period;
50916
+ expect(period2.SegmentList).toBeUndefined();
50917
+ expect(period2.EventStream).toEqual([]);
50918
+ expect((_a3 = period2.AdaptationSet) == null ? void 0 : _a3.length).toBe(1);
50640
50919
  expect(zero.id).toBe("zero");
50641
50920
  });
50642
50921
  it("imports a Period without AdaptationSets", async () => {
@@ -52314,7 +52593,7 @@ x`);
52314
52593
  // test/unit/track/dash/util/uriResolution.test.ts
52315
52594
  describe("resolveDashUri", () => {
52316
52595
  let manifest3;
52317
- let period;
52596
+ let period2;
52318
52597
  let adaptationSet;
52319
52598
  let representation;
52320
52599
  let deps;
@@ -52324,13 +52603,13 @@ x`);
52324
52603
  baseUrlSelector: pickFirstBaseUrlSelector
52325
52604
  };
52326
52605
  manifest3 = clone(mockDashManifest);
52327
- period = manifest3.MPD.Period[0];
52328
- adaptationSet = period.AdaptationSet[0];
52606
+ period2 = manifest3.MPD.Period[0];
52607
+ adaptationSet = period2.AdaptationSet[0];
52329
52608
  representation = adaptationSet.Representation[0];
52330
52609
  });
52331
52610
  function setBaseUrls(mpdUri, periodUri, adaptationSetUri, representationUri) {
52332
52611
  manifest3.MPD.BaseURL = mpdUri ? [{ _content: mpdUri }] : [];
52333
- period.BaseURL = periodUri ? [{ _content: periodUri }] : [];
52612
+ period2.BaseURL = periodUri ? [{ _content: periodUri }] : [];
52334
52613
  adaptationSet.BaseURL = adaptationSetUri ? [{ _content: adaptationSetUri }] : [];
52335
52614
  representation.BaseURL = representationUri ? [{ _content: representationUri }] : [];
52336
52615
  }
@@ -52419,7 +52698,7 @@ x`);
52419
52698
  manifest3.MPD.BaseURL = [
52420
52699
  { _content: "", serviceLocation: "mpdLevel" }
52421
52700
  ];
52422
- period.BaseURL = [{ _content: "", serviceLocation: "periodLevel" }];
52701
+ period2.BaseURL = [{ _content: "", serviceLocation: "periodLevel" }];
52423
52702
  representation.BaseURL = [
52424
52703
  { _content: "", serviceLocation: "representationLevel" }
52425
52704
  ];
@@ -53988,7 +54267,8 @@ x`);
53988
54267
  type: "hls",
53989
54268
  manifestProvider
53990
54269
  });
53991
- const deps = createContainer(factories).dependencies;
54270
+ const container = createContainer(factories);
54271
+ const deps = container.dependencies;
53992
54272
  expect(deps).toEqual(
53993
54273
  objectContaining20({
53994
54274
  segmentRequestInit: void 0,
@@ -54001,6 +54281,7 @@ x`);
54001
54281
  qualitySelector: any27(QualitySelectorImpl)
54002
54282
  })
54003
54283
  );
54284
+ container.dispose();
54004
54285
  });
54005
54286
  it("wires per-track option observables from the player options", () => {
54006
54287
  const factoryCreator = createHlsFactories(null);
@@ -54009,11 +54290,13 @@ x`);
54009
54290
  type: "hls",
54010
54291
  manifestProvider
54011
54292
  });
54012
- const deps = createContainer(factories).dependencies;
54293
+ const container = createContainer(factories);
54294
+ const deps = container.dependencies;
54013
54295
  const options2 = hlsFactoryDeps.options.value;
54014
54296
  expect(deps.audio.value).toBe(options2.audio);
54015
54297
  expect(deps.allowedContentTypes.value).toBe(options2.allowedContentTypes);
54016
54298
  expect(deps.abr.value).toBe(options2.abr);
54299
+ container.dispose();
54017
54300
  });
54018
54301
  it("exposes the shared adController without owning it", () => {
54019
54302
  const factoryCreator = createHlsFactories(null);
@@ -54044,8 +54327,10 @@ x`);
54044
54327
  type: "hls",
54045
54328
  manifestProvider
54046
54329
  });
54047
- const deps = createContainer(factories).dependencies;
54330
+ const container = createContainer(factories);
54331
+ const deps = container.dependencies;
54048
54332
  expect(deps.contentStreamFactory("audio")).toEqual(any27(Object));
54333
+ container.dispose();
54049
54334
  });
54050
54335
  it("uses createUrlHlsManifestProvider when no manifestProvider given", () => {
54051
54336
  const factoryCreator = createHlsFactories(null);
@@ -54053,8 +54338,10 @@ x`);
54053
54338
  uri: "https://example.com/main.m3u8",
54054
54339
  type: "hls"
54055
54340
  });
54056
- const deps = createContainer(factories).dependencies;
54341
+ const container = createContainer(factories);
54342
+ const deps = container.dependencies;
54057
54343
  expect(deps.manifestController).toEqual(any27(ManifestControllerImpl));
54344
+ container.dispose();
54058
54345
  });
54059
54346
  it("creates a sidecar text track controller and populates from manifest", async () => {
54060
54347
  const factoryCreator = createHlsFactories(null);
@@ -54079,13 +54366,15 @@ x`);
54079
54366
  type: "hls",
54080
54367
  manifestProvider: provider
54081
54368
  });
54082
- const deps = createContainer(factories).dependencies;
54369
+ const container = createContainer(factories);
54370
+ const deps = container.dependencies;
54083
54371
  const controller = deps.textTrackController;
54084
54372
  await deps.manifestTransformed.value;
54085
54373
  await new Promise((r) => setTimeout(r, 0));
54086
54374
  expect(controller).toBeDefined();
54087
54375
  expect(controller.textTracks.length).toBe(1);
54088
54376
  expect(controller.textTracks[0].language).toBe("en");
54377
+ container.dispose();
54089
54378
  });
54090
54379
  it("text track controller swallows manifest fetch errors", async () => {
54091
54380
  const factoryCreator = createHlsFactories(null);
@@ -54097,11 +54386,13 @@ x`);
54097
54386
  type: "hls",
54098
54387
  manifestProvider: provider
54099
54388
  });
54100
- const deps = createContainer(factories).dependencies;
54389
+ const container = createContainer(factories);
54390
+ const deps = container.dependencies;
54101
54391
  const controller = deps.textTrackController;
54102
54392
  await deps.manifestTransformed.value.catch(() => void 0);
54103
54393
  await new Promise((r) => setTimeout(r, 0));
54104
54394
  expect(controller.textTracks).toEqual([]);
54395
+ container.dispose();
54105
54396
  });
54106
54397
  describe("ad interstitial discovery", () => {
54107
54398
  function interstitialManifest(overrides = {}) {
@@ -54132,11 +54423,13 @@ x`);
54132
54423
  type: "hls",
54133
54424
  manifestProvider: provider
54134
54425
  });
54135
- const deps = createContainer(factories).dependencies;
54426
+ const container = createContainer(factories);
54427
+ const deps = container.dependencies;
54136
54428
  const timeline = await deps.mediaTimeline.value;
54137
54429
  const adBreaks = await timeline.getAdBreaks();
54138
54430
  expect(adBreaks.length).toBe(1);
54139
54431
  expect(adBreaks[0].id).toBe("ad1");
54432
+ container.dispose();
54140
54433
  });
54141
54434
  it("merges stitched SCTE-35 breaks with interstitials by start time", async () => {
54142
54435
  const factoryCreator = createHlsFactories(null);
@@ -54177,7 +54470,8 @@ x`);
54177
54470
  type: "hls",
54178
54471
  manifestProvider: provider
54179
54472
  });
54180
- const deps = createContainer(factories).dependencies;
54473
+ const container = createContainer(factories);
54474
+ const deps = container.dependencies;
54181
54475
  const timeline = await deps.mediaTimeline.value;
54182
54476
  const adBreaks = await timeline.getAdBreaks();
54183
54477
  expect(
@@ -54186,6 +54480,7 @@ x`);
54186
54480
  ["splice-1", 2, "stitched"],
54187
54481
  ["ad1", 11, "interstitial"]
54188
54482
  ]);
54483
+ container.dispose();
54189
54484
  });
54190
54485
  it("omits ad breaks when the playlist has none", async () => {
54191
54486
  const factoryCreator = createHlsFactories(null);
@@ -54194,9 +54489,11 @@ x`);
54194
54489
  type: "hls",
54195
54490
  manifestProvider
54196
54491
  });
54197
- const deps = createContainer(factories).dependencies;
54492
+ const container = createContainer(factories);
54493
+ const deps = container.dependencies;
54198
54494
  const timeline = await deps.mediaTimeline.value;
54199
54495
  expect(await timeline.getAdBreaks()).toEqual([]);
54496
+ container.dispose();
54200
54497
  });
54201
54498
  it("discovers ads against a live (non-ended) playlist", async () => {
54202
54499
  const factoryCreator = createHlsFactories(null);
@@ -54208,9 +54505,11 @@ x`);
54208
54505
  type: "hls",
54209
54506
  manifestProvider: provider
54210
54507
  });
54211
- const deps = createContainer(factories).dependencies;
54508
+ const container = createContainer(factories);
54509
+ const deps = container.dependencies;
54212
54510
  const timeline = await deps.mediaTimeline.value;
54213
54511
  expect((await timeline.getAdBreaks()).length).toBe(1);
54512
+ container.dispose();
54214
54513
  });
54215
54514
  it("returns no ad breaks when there are no variants", async () => {
54216
54515
  const factoryCreator = createHlsFactories(null);
@@ -54226,9 +54525,11 @@ x`);
54226
54525
  type: "hls",
54227
54526
  manifestProvider: provider
54228
54527
  });
54229
- const deps = createContainer(factories).dependencies;
54528
+ const container = createContainer(factories);
54529
+ const deps = container.dependencies;
54230
54530
  const timeline = await deps.mediaTimeline.value;
54231
54531
  expect(await timeline.getAdBreaks()).toEqual([]);
54532
+ container.dispose();
54232
54533
  });
54233
54534
  it("surfaces media playlist fetch errors from getAdBreaks", async () => {
54234
54535
  const factoryCreator = createHlsFactories(null);
@@ -54242,11 +54543,13 @@ x`);
54242
54543
  type: "hls",
54243
54544
  manifestProvider: provider
54244
54545
  });
54245
- const deps = createContainer(factories).dependencies;
54546
+ const container = createContainer(factories);
54547
+ const deps = container.dependencies;
54246
54548
  const timeline = await deps.mediaTimeline.value;
54247
54549
  await expectAsync(timeline.getAdBreaks()).toBeRejectedWithError(
54248
54550
  "media down"
54249
54551
  );
54552
+ container.dispose();
54250
54553
  });
54251
54554
  });
54252
54555
  });
@@ -59738,10 +60041,11 @@ x`);
59738
60041
  let player;
59739
60042
  beforeEach(() => {
59740
60043
  base = createMockVinylDependencies();
59741
- adController = new AdControllerImpl({
59742
- playbackController: base.playbackController
60044
+ depFactories = __spreadProps(__spreadValues({}, externalDependencies(base)), {
60045
+ adController: () => adController = new AdControllerImpl({
60046
+ playbackController: base.playbackController
60047
+ })
59743
60048
  });
59744
- depFactories = externalDependencies(__spreadProps(__spreadValues({}, base), { adController }));
59745
60049
  player = createVinylPlayer(
59746
60050
  { media: new MockHTMLAudioElement() },
59747
60051
  depFactories
@@ -60682,6 +60986,34 @@ x`);
60682
60986
  }
60683
60987
  });
60684
60988
 
60989
+ // test/integ/errata/mseChangeTypeSequence.test.ts
60990
+ var WEBKIT_CHANGE_TYPE_SEQUENCE_BUG = "https://bugs.webkit.org/show_bug.cgi?id=327788";
60991
+ async function loadTestBed() {
60992
+ if (!window.runChangeTypeSequenceRepro) {
60993
+ await new Promise((resolve, reject) => {
60994
+ const script = document.createElement("script");
60995
+ script.src = "errata/mse-changetype-sequence.js";
60996
+ script.onload = () => resolve();
60997
+ script.onerror = () => reject(new Error(`failed to load ${script.src}`));
60998
+ document.head.append(script);
60999
+ });
61000
+ }
61001
+ return window.runChangeTypeSequenceRepro;
61002
+ }
61003
+ describe("errata", () => {
61004
+ it("continues the buffered media after changeType() in sequence mode", async () => {
61005
+ const result = await (await loadTestBed())();
61006
+ if (!result.supported)
61007
+ pending("changeType() or its codecs are not supported");
61008
+ if (!result.contiguous && hasBrowser("WebKit" /* WEBKIT */)) {
61009
+ pending(
61010
+ `WebKit appends at the media time after changeType(): ${WEBKIT_CHANGE_TYPE_SEQUENCE_BUG} ${JSON.stringify(result)}`
61011
+ );
61012
+ }
61013
+ expect(result.after).withContext(JSON.stringify(result)).toEqual([[result.before[0][0], result.before[0][1] + 2]]);
61014
+ });
61015
+ });
61016
+
60685
61017
  // test/integ/event/looped.test.ts
60686
61018
  describe("looped integ", () => {
60687
61019
  const suite = createVinylSuite();
@@ -60995,15 +61327,19 @@ x`);
60995
61327
  timeout: 5,
60996
61328
  timeoutMessage: "waiting after seek to unbuffered region timed out after {time}s"
60997
61329
  });
60998
- const seekPromise = player.seekTo(22);
60999
- await nextWaiting;
61000
- nextWaited = waitedSpy.next(
61001
- 5,
61002
- "waited after data buffered 2 timed out after {timeout}s"
61003
- );
61004
- await mediaSource.appendNext();
61005
- await nextWaited;
61006
- await seekPromise;
61330
+ await Promise.all([
61331
+ player.seekTo(22),
61332
+ // unbuffered region
61333
+ (async () => {
61334
+ await nextWaiting;
61335
+ nextWaited = waitedSpy.next(
61336
+ 5,
61337
+ "waited after data buffered 2 timed out after {timeout}s"
61338
+ );
61339
+ await mediaSource.appendNext();
61340
+ await nextWaited;
61341
+ })()
61342
+ ]);
61007
61343
  });
61008
61344
  });
61009
61345
  });
@@ -61105,21 +61441,17 @@ x`);
61105
61441
  describe("PlaybackControllerImpl integ", () => {
61106
61442
  let media;
61107
61443
  let controller;
61108
- let originalMuted;
61109
61444
  setTestTimeout(25);
61110
61445
  beforeEach(() => {
61111
61446
  media = mediaRef.value;
61112
- originalMuted = media.muted;
61113
- if (!media.muted) {
61114
- media.muted = true;
61115
- }
61447
+ media.muted = true;
61116
61448
  controller = new PlaybackControllerImpl({
61117
61449
  media,
61118
61450
  loudnessNormalizationController: new MockLoudnessNormalizationController()
61119
61451
  });
61120
61452
  });
61121
61453
  afterEach(() => {
61122
- media.muted = originalMuted;
61454
+ media.muted = false;
61123
61455
  controller.dispose();
61124
61456
  });
61125
61457
  describe("mutedChange", () => {
@@ -61592,6 +61924,58 @@ x`);
61592
61924
  });
61593
61925
  });
61594
61926
 
61927
+ // test/integ/track/dash/periodCodecChange.test.ts
61928
+ var SEGMENTS_BASE = "https://assets.dev.vinyl.music.amazon.dev/dash/vinyl_ad_breaks_av/segments/";
61929
+ function period(id, start, rendition, codecs, startNumber, mediaStart) {
61930
+ const timescale = 15360;
61931
+ const t = mediaStart * timescale;
61932
+ return `
61933
+ <Period id="${id}" start="PT${start}S" duration="PT8S">
61934
+ <AdaptationSet contentType="video" mimeType="video/mp4" segmentAlignment="true">
61935
+ <Representation id="${id}-video" bandwidth="1000000" codecs="${codecs}" width="640" height="360">
61936
+ <SegmentTemplate timescale="${timescale}" initialization="${rendition}/init.mp4" media="${rendition}/part_$Number$.m4s" startNumber="${startNumber}" presentationTimeOffset="${t}">
61937
+ <SegmentTimeline><S t="${t}" d="30720" r="3"/></SegmentTimeline>
61938
+ </SegmentTemplate>
61939
+ </Representation>
61940
+ </AdaptationSet>
61941
+ </Period>`;
61942
+ }
61943
+ var PERIOD_CODEC_CHANGE_MPD = `<?xml version="1.0" encoding="UTF-8"?>
61944
+ <MPD xmlns="urn:mpeg:dash:schema:mpd:2011" profiles="urn:mpeg:dash:profile:isoff-live:2011" type="static" minBufferTime="PT2S" mediaPresentationDuration="PT16S">
61945
+ ${period("first", 0, "libx264_640x360_30fps_600k", "avc1.64001e", 1, 0)}
61946
+ ${period("second", 8, "libx264_1280x720_30fps_1500k", "avc1.64001f", 31, 60)}
61947
+ </MPD>`;
61948
+ describe("dash Period codec change integ", () => {
61949
+ const suite = createVinylSuite({}, { timeout: 60 });
61950
+ beforeEach(() => {
61951
+ if (!supportsMse()) pending("MSE not supported");
61952
+ if (!("changeType" in SourceBuffer.prototype))
61953
+ pending("SourceBuffer.changeType not supported");
61954
+ });
61955
+ const loadOptions = {
61956
+ type: "dash",
61957
+ uri: "test://period-codec-change",
61958
+ manifestProvider: () => Promise.resolve({
61959
+ manifest: parseDashManifest(PERIOD_CODEC_CHANGE_MPD),
61960
+ baseUrl: SEGMENTS_BASE
61961
+ })
61962
+ };
61963
+ it("plays across a Period boundary that changes codec", async () => {
61964
+ const changeType = spyOn(
61965
+ SourceBuffer.prototype,
61966
+ "changeType"
61967
+ ).and.callThrough();
61968
+ const player = suite.player;
61969
+ player.load(loadOptions);
61970
+ await player.play().catch(() => void 0);
61971
+ await player.seekTo(6, 0.5).catch(() => void 0);
61972
+ expect(await poll(() => player.currentTime >= 10, { timeout: 20 })).withContext(`plays past the boundary (at ${player.currentTime})`).toBeTrue();
61973
+ expect(changeType).toHaveBeenCalledWith(
61974
+ 'video/mp4; codecs="avc1.64001f"'
61975
+ );
61976
+ });
61977
+ });
61978
+
61595
61979
  // test/integ/track/dash/Uhd.test.ts
61596
61980
  describe("uhd integ", () => {
61597
61981
  class ForceUhdCapabilities extends CapabilitiesImpl {