@amazon/vinyl 3.2.2 → 3.2.3-next.20261001224604
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.
- package/README.md +2 -2
- package/dist/index.cjs +62 -21
- package/dist/index.cjs.map +3 -3
- package/dist/index.js +65 -22
- package/dist/index.js.map +3 -3
- package/dist/test/benchmark.es5.js +7 -6
- package/dist/test/benchmark.js +35 -30
- package/dist/test/benchmark.js.map +3 -3
- package/dist/test/integ.es5.js +184 -171
- package/dist/test/integ.js +450 -165
- package/dist/test/integ.js.map +4 -4
- package/dist/types/current/ad/AdControllerImpl.d.ts.map +1 -1
- package/dist/types/current/ad/AdControllerImpl.js +15 -1
- package/dist/types/current/ad/discoverHlsInterstitials.js +13 -1
- package/dist/types/current/drm/commonEme/MsCommonEme.d.ts.map +1 -1
- package/dist/types/current/drm/commonEme/MsCommonEme.js +2 -2
- package/dist/types/current/drm/commonEme/StandardCommonEme.d.ts.map +1 -1
- package/dist/types/current/drm/commonEme/StandardCommonEme.js +3 -2
- package/dist/types/current/drm/commonEme/WebKitCommonEme.d.ts.map +1 -1
- package/dist/types/current/drm/commonEme/WebKitCommonEme.js +2 -2
- package/dist/types/current/drm/dom/MSMediaKeys.d.ts +1 -1
- package/dist/types/current/drm/dom/MSMediaKeys.d.ts.map +1 -1
- package/dist/types/current/drm/dom/WebKitMediaKeys.d.ts +1 -1
- package/dist/types/current/drm/dom/WebKitMediaKeys.d.ts.map +1 -1
- package/dist/types/current/drm/util/extractContentId.js +2 -2
- package/dist/types/current/playback/PlaybackControllerImpl.d.ts +1 -1
- package/dist/types/current/streaming/MediaQualityMetadata.d.ts +3 -1
- package/dist/types/current/streaming/MediaQualityMetadata.d.ts.map +1 -1
- package/dist/types/current/streaming/SegmentControllerImpl.d.ts +1 -1
- package/dist/types/current/streaming/buffering/BufferingController.d.ts +1 -1
- package/dist/types/current/streaming/buffering/BufferingController.d.ts.map +1 -1
- package/dist/types/current/streaming/buffering/BufferingController.js +14 -5
- package/dist/types/current/streaming/buffering/MediaSourceController.d.ts.map +1 -1
- package/dist/types/current/streaming/buffering/MediaSourceController.js +4 -0
- package/dist/types/current/text/discoverDashTextTracks.d.ts +2 -2
- package/dist/types/current/text/discoverDashTextTracks.js +4 -3
- package/dist/types/current/text/parseWebVtt.d.ts.map +1 -1
- package/dist/types/current/text/parseWebVtt.js +3 -2
- package/dist/types/current/track/TrackController.d.ts.map +1 -1
- package/dist/types/current/track/TrackController.js +7 -0
- package/dist/types/current/track/hls/HlsManifestData.d.ts +14 -1
- package/dist/types/current/track/hls/HlsManifestData.d.ts.map +1 -1
- package/dist/types/current/track/hls/buildHlsMediaTimeline.d.ts.map +1 -1
- package/dist/types/current/track/hls/buildHlsMediaTimeline.js +10 -2
- package/dist/types/current/track/hls/createUrlHlsManifestProvider.d.ts +3 -2
- package/dist/types/current/track/hls/createUrlHlsManifestProvider.d.ts.map +1 -1
- package/dist/types/current/track/hls/createUrlHlsManifestProvider.js +8 -3
- package/dist/types/current/tsconfig.tsbuildinfo +1 -1
- package/dist/types/ts3.7/playback/PlaybackControllerImpl.d.ts +1 -1
- package/dist/types/ts3.7/streaming/MediaQualityMetadata.d.ts +3 -1
- package/dist/types/ts3.7/streaming/SegmentControllerImpl.d.ts +1 -1
- package/dist/types/ts3.7/streaming/buffering/BufferingController.d.ts +1 -1
- package/dist/types/ts3.7/text/discoverDashTextTracks.d.ts +2 -2
- package/dist/types/ts3.7/track/hls/HlsManifestData.d.ts +14 -1
- package/dist/types/ts3.7/track/hls/createUrlHlsManifestProvider.d.ts +3 -2
- package/dist/types/ts4.1/playback/PlaybackControllerImpl.d.ts +1 -1
- package/dist/types/ts4.1/streaming/MediaQualityMetadata.d.ts +3 -1
- package/dist/types/ts4.1/streaming/SegmentControllerImpl.d.ts +1 -1
- package/dist/types/ts4.1/streaming/buffering/BufferingController.d.ts +1 -1
- package/dist/types/ts4.1/text/discoverDashTextTracks.d.ts +2 -2
- package/dist/types/ts4.1/track/hls/HlsManifestData.d.ts +14 -1
- package/dist/types/ts4.1/track/hls/createUrlHlsManifestProvider.d.ts +3 -2
- package/dist/types/ts4.7/playback/PlaybackControllerImpl.d.ts +1 -1
- package/dist/types/ts4.7/streaming/MediaQualityMetadata.d.ts +3 -1
- package/dist/types/ts4.7/streaming/SegmentControllerImpl.d.ts +1 -1
- package/dist/types/ts4.7/streaming/buffering/BufferingController.d.ts +1 -1
- package/dist/types/ts4.7/text/discoverDashTextTracks.d.ts +2 -2
- package/dist/types/ts4.7/track/hls/HlsManifestData.d.ts +14 -1
- package/dist/types/ts4.7/track/hls/createUrlHlsManifestProvider.d.ts +3 -2
- package/dist/unit/types/current/ad/AdControllerImpl.test.js +66 -0
- package/dist/unit/types/current/ad/discoverHlsInterstitials.test.js +29 -2
- package/dist/unit/types/current/drm/commonEme/StandardCommonEme.test.js +12 -4
- package/dist/unit/types/current/drm/util/extractContentId.test.js +7 -0
- package/dist/unit/types/current/index.d.ts +1 -0
- package/dist/unit/types/current/index.d.ts.map +1 -1
- package/dist/unit/types/current/index.js +1 -0
- package/dist/unit/types/current/streaming/MediaQualityMetadata.test.js +8 -0
- package/dist/unit/types/current/streaming/buffering/BufferingController.test.js +26 -0
- package/dist/unit/types/current/streaming/buffering/MediaSourceController.test.js +29 -0
- package/dist/unit/types/current/text/TextTrack.test.d.ts +2 -0
- package/dist/unit/types/current/text/TextTrack.test.d.ts.map +1 -0
- package/dist/unit/types/current/text/TextTrack.test.js +12 -0
- package/dist/unit/types/current/text/discoverDashTextTracks.test.js +17 -0
- package/dist/unit/types/current/text/parseWebVtt.test.js +26 -0
- package/dist/unit/types/current/track/TrackController.test.js +15 -60
- package/dist/unit/types/current/track/hls/buildHlsMediaTimeline.test.js +22 -0
- package/dist/unit/types/current/track/hls/createUrlHlsManifestProvider.test.js +23 -0
- package/dist/unit/types/current/tsconfig.tsbuildinfo +1 -1
- package/dist/vinylTestUtil/types/current/tsconfig.tsbuildinfo +1 -1
- package/docs/CUSTOMIZATION_GUIDE.md +310 -0
- package/package.json +10 -10
- package/docs/DASH_MANIFEST_TRANSFORM_GUIDE.md +0 -236
package/dist/test/integ.js
CHANGED
|
@@ -5832,7 +5832,8 @@
|
|
|
5832
5832
|
return true;
|
|
5833
5833
|
}
|
|
5834
5834
|
/**
|
|
5835
|
-
* Executes a provided function once per each key/value pair in the Map,
|
|
5835
|
+
* Executes a provided function once per each key/value pair in the Map,
|
|
5836
|
+
* ordered from least recently used to most.
|
|
5836
5837
|
*
|
|
5837
5838
|
* @param callback A callback to invoke for every element in the cache.
|
|
5838
5839
|
* @param thisArg Value to use as this when executing callback
|
|
@@ -5877,8 +5878,8 @@
|
|
|
5877
5878
|
let value = void 0;
|
|
5878
5879
|
const memoized = () => {
|
|
5879
5880
|
if (!cached) {
|
|
5880
|
-
cached = true;
|
|
5881
5881
|
value = inner();
|
|
5882
|
+
cached = true;
|
|
5882
5883
|
}
|
|
5883
5884
|
return value;
|
|
5884
5885
|
};
|
|
@@ -5907,9 +5908,9 @@
|
|
|
5907
5908
|
const memoized = (...args) => {
|
|
5908
5909
|
const key = keyProvider(...args);
|
|
5909
5910
|
if (!hasValue || cachedKey !== key) {
|
|
5910
|
-
hasValue = true;
|
|
5911
|
-
cachedKey = key;
|
|
5912
5911
|
cachedValue = inner(...args);
|
|
5912
|
+
cachedKey = key;
|
|
5913
|
+
hasValue = true;
|
|
5913
5914
|
}
|
|
5914
5915
|
return cachedValue;
|
|
5915
5916
|
};
|
|
@@ -5972,7 +5973,8 @@
|
|
|
5972
5973
|
charCode === 13 || // '\r' (carriage return)
|
|
5973
5974
|
charCode === 10;
|
|
5974
5975
|
}
|
|
5975
|
-
var encodedEntitiesRegex = /&(
|
|
5976
|
+
var encodedEntitiesRegex = /&(?:#(?:x([\da-f]+)|(\d+))|(\w+));/gi;
|
|
5977
|
+
var MAX_CODE_POINT = 1114111;
|
|
5976
5978
|
var predefinedDecodeEntities = /* @__PURE__ */ new Map([
|
|
5977
5979
|
["apos", "'"],
|
|
5978
5980
|
["amp", "&"],
|
|
@@ -5981,20 +5983,22 @@
|
|
|
5981
5983
|
["quot", '"']
|
|
5982
5984
|
]);
|
|
5983
5985
|
function decodeEntities(str, namedEntities = predefinedDecodeEntities) {
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
const entityValue = namedEntities.get(entityName.toLowerCase());
|
|
5991
|
-
if (!entityValue) return substring;
|
|
5992
|
-
return entityValue;
|
|
5986
|
+
return str.replace(
|
|
5987
|
+
encodedEntitiesRegex,
|
|
5988
|
+
(substring, hex, decimal, entityName) => {
|
|
5989
|
+
var _a3;
|
|
5990
|
+
if (hex == null && decimal == null) {
|
|
5991
|
+
return (_a3 = namedEntities.get(entityName.toLowerCase())) != null ? _a3 : substring;
|
|
5993
5992
|
}
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5993
|
+
const codePoint = hex != null ? parseInt(hex, 16) : parseInt(decimal, 10);
|
|
5994
|
+
if (codePoint > MAX_CODE_POINT || isSurrogate(codePoint))
|
|
5995
|
+
return substring;
|
|
5996
|
+
return String.fromCodePoint(codePoint);
|
|
5997
|
+
}
|
|
5998
|
+
);
|
|
5999
|
+
}
|
|
6000
|
+
function isSurrogate(codePoint) {
|
|
6001
|
+
return codePoint >= 55296 && codePoint <= 57343;
|
|
5998
6002
|
}
|
|
5999
6003
|
var standardEntityValueToNames = flipMap(predefinedDecodeEntities);
|
|
6000
6004
|
function eqStr(a, b, ignoreCase = false) {
|
|
@@ -8056,7 +8060,11 @@ ${this.lastInitStack}` : "";
|
|
|
8056
8060
|
__publicField(this, "onDownloadSpeedChange", () => {
|
|
8057
8061
|
var _a3;
|
|
8058
8062
|
const downlink = (_a3 = this.deps.networkInformation) == null ? void 0 : _a3.downlink;
|
|
8059
|
-
const estimatedSpeed = downlink ?
|
|
8063
|
+
const estimatedSpeed = downlink ? (
|
|
8064
|
+
// Megabits are decimal, matching the measured `bytes * 8 / seconds`
|
|
8065
|
+
// this estimate is averaged with.
|
|
8066
|
+
downlink * 1e6
|
|
8067
|
+
) : this.options.unknownDownlinkBandwidthEstimate;
|
|
8060
8068
|
updateStatMetrics(
|
|
8061
8069
|
this._metrics.estimatedDownlinkBandwidth,
|
|
8062
8070
|
estimatedSpeed,
|
|
@@ -8546,38 +8554,41 @@ ${this.lastInitStack}` : "";
|
|
|
8546
8554
|
this.dispatch("request", { requestInfo });
|
|
8547
8555
|
let lastResult = null;
|
|
8548
8556
|
let currentTry = 0;
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
this.dispatch("requestAttemptStart", {
|
|
8556
|
-
requestInfo,
|
|
8557
|
-
attemptInfo
|
|
8558
|
-
});
|
|
8559
|
-
lastResult = await this.doRequest(
|
|
8560
|
-
requestInfo,
|
|
8561
|
-
requestOptions,
|
|
8562
|
-
attemptInfo,
|
|
8563
|
-
timeoutController
|
|
8564
|
-
).catch((reason) => {
|
|
8565
|
-
var _a4;
|
|
8566
|
-
const completeInfo = {
|
|
8567
|
-
ok: false,
|
|
8568
|
-
type: ((_a4 = requestOptions.abort) == null ? void 0 : _a4.aborted()) ? "abort" /* ABORT */ : "internal" /* INTERNAL */,
|
|
8569
|
-
requestInfo,
|
|
8570
|
-
reason,
|
|
8571
|
-
willRetry: false,
|
|
8572
|
-
timestamp: Date.now(),
|
|
8573
|
-
retryAfter: null
|
|
8557
|
+
try {
|
|
8558
|
+
do {
|
|
8559
|
+
++currentTry;
|
|
8560
|
+
const attemptInfo = {
|
|
8561
|
+
currentTry,
|
|
8562
|
+
timestamp: Date.now()
|
|
8574
8563
|
};
|
|
8575
|
-
|
|
8576
|
-
|
|
8564
|
+
this.dispatch("requestAttemptStart", {
|
|
8565
|
+
requestInfo,
|
|
8566
|
+
attemptInfo
|
|
8567
|
+
});
|
|
8568
|
+
lastResult = await this.doRequest(
|
|
8569
|
+
requestInfo,
|
|
8570
|
+
requestOptions,
|
|
8571
|
+
attemptInfo,
|
|
8572
|
+
timeoutController
|
|
8573
|
+
).catch((reason) => {
|
|
8574
|
+
var _a4;
|
|
8575
|
+
const completeInfo = {
|
|
8576
|
+
ok: false,
|
|
8577
|
+
type: ((_a4 = requestOptions.abort) == null ? void 0 : _a4.aborted()) ? "abort" /* ABORT */ : "internal" /* INTERNAL */,
|
|
8578
|
+
requestInfo,
|
|
8579
|
+
reason,
|
|
8580
|
+
willRetry: false,
|
|
8581
|
+
timestamp: Date.now(),
|
|
8582
|
+
retryAfter: null
|
|
8583
|
+
};
|
|
8584
|
+
return { info: completeInfo, response: null };
|
|
8585
|
+
});
|
|
8586
|
+
this.reportMetricsEntry(lastResult.info);
|
|
8587
|
+
this.dispatch("requestAttemptComplete", lastResult.info);
|
|
8588
|
+
} while (!lastResult.info.ok && lastResult.info.willRetry);
|
|
8589
|
+
} finally {
|
|
8577
8590
|
timeoutController.dispose();
|
|
8578
|
-
|
|
8579
|
-
this.dispatch("requestAttemptComplete", lastResult.info);
|
|
8580
|
-
} while (!lastResult.info.ok && lastResult.info.willRetry);
|
|
8591
|
+
}
|
|
8581
8592
|
this.dispatch("requestComplete", lastResult.info);
|
|
8582
8593
|
if (lastResult.info.ok) return lastResult.response;
|
|
8583
8594
|
else throw new RequestError(lastResult.response, lastResult.info);
|
|
@@ -8942,6 +8953,13 @@ ${this.lastInitStack}` : "";
|
|
|
8942
8953
|
function bufferToByteArray(buffer) {
|
|
8943
8954
|
return buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
8944
8955
|
}
|
|
8956
|
+
function bufferToArrayBuffer(buffer) {
|
|
8957
|
+
if (buffer instanceof ArrayBuffer) return buffer;
|
|
8958
|
+
return buffer.buffer.slice(
|
|
8959
|
+
buffer.byteOffset,
|
|
8960
|
+
buffer.byteOffset + buffer.byteLength
|
|
8961
|
+
);
|
|
8962
|
+
}
|
|
8945
8963
|
function buffersEqual(bufferA, bufferB) {
|
|
8946
8964
|
if (bufferA === bufferB) return true;
|
|
8947
8965
|
if (!bufferA && !bufferB) return true;
|
|
@@ -10268,7 +10286,11 @@ ${this.lastInitStack}` : "";
|
|
|
10268
10286
|
logVerbose(this, "nextAd");
|
|
10269
10287
|
try {
|
|
10270
10288
|
const ad = await adBreakState2.nextAd();
|
|
10271
|
-
if (this.disposed
|
|
10289
|
+
if (this.disposed) return;
|
|
10290
|
+
if (adBreakState2.completedReason) {
|
|
10291
|
+
if (!this.adBreakState) await nextBreak();
|
|
10292
|
+
return;
|
|
10293
|
+
}
|
|
10272
10294
|
if (ad) {
|
|
10273
10295
|
this.startAd(ad);
|
|
10274
10296
|
} else {
|
|
@@ -10402,12 +10424,18 @@ ${this.lastInitStack}` : "";
|
|
|
10402
10424
|
const currProgress = pC.currentTimePercent;
|
|
10403
10425
|
const progressStart = adState.timeStart / pC.duration;
|
|
10404
10426
|
if (!adState.quartile.first && currProgress > 0.25 && progressStart < AD_START_TOLERANCE) {
|
|
10427
|
+
adState.quartile.first = true;
|
|
10428
|
+
logDebug(this, "adFirstQuartile", adState.ad);
|
|
10405
10429
|
this.dispatch("adFirstQuartile", createAdProgressEvent(adState));
|
|
10406
10430
|
}
|
|
10407
10431
|
if (!adState.quartile.midpoint && currProgress > 0.5 && progressStart < 0.25 + AD_START_TOLERANCE) {
|
|
10432
|
+
adState.quartile.midpoint = true;
|
|
10433
|
+
logDebug(this, "adMidpoint", adState.ad);
|
|
10408
10434
|
this.dispatch("adMidpoint", createAdProgressEvent(adState));
|
|
10409
10435
|
}
|
|
10410
10436
|
if (!adState.quartile.third && currProgress > 0.75 && progressStart < 0.5 + AD_START_TOLERANCE) {
|
|
10437
|
+
adState.quartile.third = true;
|
|
10438
|
+
logDebug(this, "adThirdQuartile", adState.ad);
|
|
10411
10439
|
this.dispatch("adThirdQuartile", createAdProgressEvent(adState));
|
|
10412
10440
|
}
|
|
10413
10441
|
}
|
|
@@ -11143,7 +11171,9 @@ ${this.lastInitStack}` : "";
|
|
|
11143
11171
|
(length) => length === validators.length
|
|
11144
11172
|
);
|
|
11145
11173
|
return createDeepValidator(
|
|
11146
|
-
substitute(locale10.tuple, {
|
|
11174
|
+
substitute(locale10.tuple, {
|
|
11175
|
+
value: validators.map((validator) => validator.description).join(", ")
|
|
11176
|
+
}),
|
|
11147
11177
|
(input, options, path) => {
|
|
11148
11178
|
const errors = [];
|
|
11149
11179
|
errors.push(
|
|
@@ -11448,7 +11478,7 @@ ${this.lastInitStack}` : "";
|
|
|
11448
11478
|
};
|
|
11449
11479
|
var _NumberSchema = class _NumberSchema extends ValueSchema {
|
|
11450
11480
|
/**
|
|
11451
|
-
* The base
|
|
11481
|
+
* The base NumberSchema instance validating that the input is a number.
|
|
11452
11482
|
*/
|
|
11453
11483
|
static get base() {
|
|
11454
11484
|
if (this._base == null)
|
|
@@ -11734,7 +11764,7 @@ ${this.lastInitStack}` : "";
|
|
|
11734
11764
|
};
|
|
11735
11765
|
var _StringSchema = class _StringSchema extends ValueSchema {
|
|
11736
11766
|
/**
|
|
11737
|
-
* The base
|
|
11767
|
+
* The base StringSchema instance validating that the input is a string.
|
|
11738
11768
|
*/
|
|
11739
11769
|
static get base() {
|
|
11740
11770
|
if (this._base == null)
|
|
@@ -12515,6 +12545,7 @@ ${this.lastInitStack}` : "";
|
|
|
12515
12545
|
const url = resolveUrl(assetListUrl, baseUrl);
|
|
12516
12546
|
const response = await requestWithRetry(url);
|
|
12517
12547
|
const json = await readResponseBody(response, "json");
|
|
12548
|
+
const assetListBaseUrl = response.url || url;
|
|
12518
12549
|
const assets = (_a3 = json.ASSETS) != null ? _a3 : [];
|
|
12519
12550
|
const ads = assets.map((asset, i) => {
|
|
12520
12551
|
var _a4;
|
|
@@ -12522,7 +12553,14 @@ ${this.lastInitStack}` : "";
|
|
|
12522
12553
|
id: `${rangeId}-${i}`,
|
|
12523
12554
|
startTime,
|
|
12524
12555
|
duration: (_a4 = asset.DURATION) != null ? _a4 : null,
|
|
12525
|
-
|
|
12556
|
+
// Each Asset-Description "URI" MUST be an absolute URI, so the base
|
|
12557
|
+
// only applies to non-conforming lists. As a leniency (not a spec
|
|
12558
|
+
// rule), resolve against the asset list the URI was read from, as
|
|
12559
|
+
// for any relative reference in a retrieved document (RFC 3986
|
|
12560
|
+
// §5.1.3): asset lists are commonly served by an ad server rather
|
|
12561
|
+
// than alongside the playlist.
|
|
12562
|
+
// @see https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis-22#appendix-D.2
|
|
12563
|
+
uri: resolveUrl(asset.URI, assetListBaseUrl)
|
|
12526
12564
|
};
|
|
12527
12565
|
});
|
|
12528
12566
|
return { ads, skipControl: parseSkipControl(json["SKIP-CONTROL"]) };
|
|
@@ -12813,7 +12851,7 @@ ${this.lastInitStack}` : "";
|
|
|
12813
12851
|
__publicField(this, "_disposed", false);
|
|
12814
12852
|
__publicField(this, "messageHandler", (event) => {
|
|
12815
12853
|
this.dispatch("message", {
|
|
12816
|
-
message: event.message
|
|
12854
|
+
message: bufferToArrayBuffer(event.message)
|
|
12817
12855
|
});
|
|
12818
12856
|
});
|
|
12819
12857
|
__publicField(this, "errorHandler", () => {
|
|
@@ -12956,11 +12994,7 @@ ${this.lastInitStack}` : "";
|
|
|
12956
12994
|
return "StandardCommonMediaKeySession";
|
|
12957
12995
|
}
|
|
12958
12996
|
generateRequest() {
|
|
12959
|
-
|
|
12960
|
-
return this.session.generateRequest(
|
|
12961
|
-
this.initDataType,
|
|
12962
|
-
initData instanceof ArrayBuffer ? initData : initData.buffer
|
|
12963
|
-
).catch(createDrmErrorHandler());
|
|
12997
|
+
return this.session.generateRequest(this.initDataType, this.initData).catch(createDrmErrorHandler());
|
|
12964
12998
|
}
|
|
12965
12999
|
update(key) {
|
|
12966
13000
|
if (this.disposed) throw new DisposedError();
|
|
@@ -13068,7 +13102,7 @@ ${this.lastInitStack}` : "";
|
|
|
13068
13102
|
__publicField(this, "_disposed", false);
|
|
13069
13103
|
__publicField(this, "messageHandler", (event) => {
|
|
13070
13104
|
this.dispatch("message", {
|
|
13071
|
-
message: event.message
|
|
13105
|
+
message: bufferToArrayBuffer(event.message)
|
|
13072
13106
|
});
|
|
13073
13107
|
});
|
|
13074
13108
|
__publicField(this, "errorHandler", () => {
|
|
@@ -13966,7 +14000,7 @@ ${this.lastInitStack}` : "";
|
|
|
13966
14000
|
|
|
13967
14001
|
// src/drm/util/extractContentId.ts
|
|
13968
14002
|
function extractContentId(initData) {
|
|
13969
|
-
const bufferStr = bufferToUtf16(initData
|
|
14003
|
+
const bufferStr = bufferToUtf16(bufferToArrayBuffer(initData));
|
|
13970
14004
|
const matches = bufferStr.match(/skd:\/\/(.+)$/);
|
|
13971
14005
|
if (!matches) {
|
|
13972
14006
|
throw new ValidationError("No contentId match", ErrorOrigin.MEDIA);
|
|
@@ -14632,20 +14666,21 @@ ${this.lastInitStack}` : "";
|
|
|
14632
14666
|
let abs = Math.abs(value);
|
|
14633
14667
|
const years = Math.floor(abs / Y);
|
|
14634
14668
|
abs -= years * Y;
|
|
14635
|
-
const months = Math.floor(abs
|
|
14669
|
+
const months = Math.floor(abs / M);
|
|
14636
14670
|
const days = Math.floor(abs % M / D);
|
|
14637
14671
|
const hours = Math.floor(abs % D / H);
|
|
14638
14672
|
const minutes = Math.floor(abs % H / I);
|
|
14639
14673
|
const seconds = abs % I;
|
|
14640
|
-
let
|
|
14641
|
-
if (years > 0)
|
|
14642
|
-
if (months > 0)
|
|
14643
|
-
if (days > 0)
|
|
14644
|
-
|
|
14645
|
-
if (hours > 0)
|
|
14646
|
-
if (minutes > 0)
|
|
14647
|
-
if (seconds > 0
|
|
14648
|
-
|
|
14674
|
+
let date = "";
|
|
14675
|
+
if (years > 0) date += `${years}Y`;
|
|
14676
|
+
if (months > 0) date += `${months}M`;
|
|
14677
|
+
if (days > 0) date += `${days}D`;
|
|
14678
|
+
let time = "";
|
|
14679
|
+
if (hours > 0) time += `${hours}H`;
|
|
14680
|
+
if (minutes > 0) time += `${minutes}M`;
|
|
14681
|
+
if (seconds > 0) time += `${roundToNearest(seconds, 1e-3)}S`;
|
|
14682
|
+
if (!date && !time) time = "0S";
|
|
14683
|
+
return `${sign}P${date}${time && `T${time}`}`;
|
|
14649
14684
|
}
|
|
14650
14685
|
|
|
14651
14686
|
// ../vinyl-mpd-parser/src/error/parsingError.ts
|
|
@@ -16791,14 +16826,16 @@ ${this.lastInitStack}` : "";
|
|
|
16791
16826
|
return;
|
|
16792
16827
|
}
|
|
16793
16828
|
const byteLength = streamingSegment.data.byteLength;
|
|
16794
|
-
|
|
16829
|
+
const remaining = byteLength - this.appendOffset;
|
|
16830
|
+
const firstAppend = this.appendOffset === 0;
|
|
16831
|
+
if (remaining > appendSize) {
|
|
16795
16832
|
const newOffset = this.appendOffset + appendSize;
|
|
16796
16833
|
const chunk = streamingSegment.data.slice(
|
|
16797
16834
|
this.appendOffset,
|
|
16798
16835
|
newOffset
|
|
16799
16836
|
);
|
|
16800
16837
|
await sourceBufferController.append(chunk);
|
|
16801
|
-
if (
|
|
16838
|
+
if (firstAppend) {
|
|
16802
16839
|
this.buffered.push(streamingSegment);
|
|
16803
16840
|
}
|
|
16804
16841
|
this.appendOffset = newOffset;
|
|
@@ -16807,9 +16844,13 @@ ${this.lastInitStack}` : "";
|
|
|
16807
16844
|
`appended chunk, this.appendOffset: ${this.appendOffset}`
|
|
16808
16845
|
);
|
|
16809
16846
|
} else {
|
|
16810
|
-
await sourceBufferController.append(
|
|
16811
|
-
|
|
16812
|
-
|
|
16847
|
+
await sourceBufferController.append(
|
|
16848
|
+
firstAppend ? streamingSegment.data : streamingSegment.data.slice(this.appendOffset)
|
|
16849
|
+
);
|
|
16850
|
+
this.appendOffset = byteLength;
|
|
16851
|
+
if (firstAppend) {
|
|
16852
|
+
this.buffered.push(streamingSegment);
|
|
16853
|
+
}
|
|
16813
16854
|
}
|
|
16814
16855
|
if (!tail) this.refreshHead();
|
|
16815
16856
|
}
|
|
@@ -17092,6 +17133,7 @@ ${this.lastInitStack}` : "";
|
|
|
17092
17133
|
this.activateDisposer.dispose();
|
|
17093
17134
|
this.activateDisposer = null;
|
|
17094
17135
|
++this.durationToken;
|
|
17136
|
+
this.durationSet = false;
|
|
17095
17137
|
try {
|
|
17096
17138
|
URL.revokeObjectURL(this.objectUrl);
|
|
17097
17139
|
} catch (error) {
|
|
@@ -17640,6 +17682,7 @@ ${this.lastInitStack}` : "";
|
|
|
17640
17682
|
dispose() {
|
|
17641
17683
|
this._disposed = true;
|
|
17642
17684
|
this.callbacks.length = 0;
|
|
17685
|
+
this.n = 0;
|
|
17643
17686
|
}
|
|
17644
17687
|
notify(value, previousValue) {
|
|
17645
17688
|
this._changeId++;
|
|
@@ -17755,23 +17798,26 @@ ${this.lastInitStack}` : "";
|
|
|
17755
17798
|
providers[key] = provider;
|
|
17756
17799
|
current[key] = provider.value;
|
|
17757
17800
|
}
|
|
17758
|
-
|
|
17801
|
+
let published = __spreadValues({}, current);
|
|
17802
|
+
const publish = (setData) => {
|
|
17803
|
+
published = __spreadValues({}, current);
|
|
17804
|
+
setData(published);
|
|
17805
|
+
};
|
|
17806
|
+
return externalData(published, (setData) => {
|
|
17759
17807
|
const subs = [];
|
|
17808
|
+
let subscribing = true;
|
|
17760
17809
|
for (const key of keys) {
|
|
17761
|
-
const provider = providers[key];
|
|
17762
|
-
let isFirst = true;
|
|
17763
17810
|
subs.push(
|
|
17764
|
-
|
|
17765
|
-
if (isFirst) {
|
|
17766
|
-
isFirst = false;
|
|
17767
|
-
return;
|
|
17768
|
-
}
|
|
17811
|
+
providers[key].onData((value) => {
|
|
17769
17812
|
current[key] = value;
|
|
17770
|
-
|
|
17813
|
+
if (!subscribing) publish(setData);
|
|
17771
17814
|
})
|
|
17772
17815
|
);
|
|
17773
17816
|
}
|
|
17774
|
-
|
|
17817
|
+
subscribing = false;
|
|
17818
|
+
if (keys.some((key) => current[key] !== published[key])) {
|
|
17819
|
+
publish(setData);
|
|
17820
|
+
}
|
|
17775
17821
|
return () => {
|
|
17776
17822
|
for (const unsub of subs) unsub();
|
|
17777
17823
|
};
|
|
@@ -19194,10 +19240,16 @@ ${this.lastInitStack}` : "";
|
|
|
19194
19240
|
return out;
|
|
19195
19241
|
}
|
|
19196
19242
|
function isTextAdaptationSet(adaptationSet) {
|
|
19243
|
+
var _a3;
|
|
19197
19244
|
if (adaptationSet.contentType === "text") return true;
|
|
19198
19245
|
const mt = adaptationSet.mimeType;
|
|
19199
19246
|
if (mt && mt.startsWith("text/")) return true;
|
|
19200
|
-
return
|
|
19247
|
+
return ((_a3 = adaptationSet.Representation) != null ? _a3 : []).some(
|
|
19248
|
+
(representation) => {
|
|
19249
|
+
var _a4;
|
|
19250
|
+
return (_a4 = representation.mimeType) == null ? void 0 : _a4.startsWith("text/");
|
|
19251
|
+
}
|
|
19252
|
+
);
|
|
19201
19253
|
}
|
|
19202
19254
|
function isSidecarTextMime(mimeType) {
|
|
19203
19255
|
if (mimeType == null) return true;
|
|
@@ -19455,7 +19507,7 @@ ${this.lastInitStack}` : "";
|
|
|
19455
19507
|
const cues = [];
|
|
19456
19508
|
const styles = [];
|
|
19457
19509
|
let i = 1;
|
|
19458
|
-
while (i < lines.length && lines[i] !== "") i++;
|
|
19510
|
+
while (i < lines.length && lines[i] !== "" && !lines[i].includes("-->")) i++;
|
|
19459
19511
|
while (i < lines.length) {
|
|
19460
19512
|
if (lines[i] === "") {
|
|
19461
19513
|
i++;
|
|
@@ -22617,7 +22669,9 @@ ${this.lastInitStack}` : "";
|
|
|
22617
22669
|
audioConfig: null,
|
|
22618
22670
|
videoConfig: null,
|
|
22619
22671
|
audioDecodeTime: 0,
|
|
22620
|
-
videoDecodeTime: 0
|
|
22672
|
+
videoDecodeTime: 0,
|
|
22673
|
+
audioTrackId: null,
|
|
22674
|
+
videoTrackId: null
|
|
22621
22675
|
};
|
|
22622
22676
|
return { transmux: (data2) => transmux(state, data2) };
|
|
22623
22677
|
}
|
|
@@ -22672,11 +22726,12 @@ ${this.lastInitStack}` : "";
|
|
|
22672
22726
|
sampleRate: sampleRate2,
|
|
22673
22727
|
audioSpecificConfig: buildAudioSpecificConfig(firstFrame)
|
|
22674
22728
|
};
|
|
22729
|
+
state.audioTrackId = 1;
|
|
22675
22730
|
buildInitSegment(
|
|
22676
22731
|
state,
|
|
22677
22732
|
moov(
|
|
22678
22733
|
audioTrak({
|
|
22679
|
-
trackId:
|
|
22734
|
+
trackId: state.audioTrackId,
|
|
22680
22735
|
sampleRate: state.audioConfig.sampleRate,
|
|
22681
22736
|
channelCount: state.audioConfig.channelConfiguration,
|
|
22682
22737
|
sampleEntry: mp4aSampleEntry(state.audioConfig)
|
|
@@ -22703,7 +22758,7 @@ ${this.lastInitStack}` : "";
|
|
|
22703
22758
|
const duration = frames.length * samplesPerFrame / sampleRate;
|
|
22704
22759
|
const moofBox = moof({
|
|
22705
22760
|
sequenceNumber: state.sequenceNumber++,
|
|
22706
|
-
trackId:
|
|
22761
|
+
trackId: state.audioTrackId,
|
|
22707
22762
|
baseDecodeTime: state.audioDecodeTime,
|
|
22708
22763
|
samples
|
|
22709
22764
|
});
|
|
@@ -22809,9 +22864,10 @@ ${this.lastInitStack}` : "";
|
|
|
22809
22864
|
if (!state.initSegment && (audioConfig || videoConfig)) {
|
|
22810
22865
|
const traks = [];
|
|
22811
22866
|
if (videoConfig) {
|
|
22867
|
+
state.videoTrackId = traks.length + 1;
|
|
22812
22868
|
traks.push(
|
|
22813
22869
|
videoTrak({
|
|
22814
|
-
trackId:
|
|
22870
|
+
trackId: state.videoTrackId,
|
|
22815
22871
|
width: videoConfig.width,
|
|
22816
22872
|
height: videoConfig.height,
|
|
22817
22873
|
sampleEntry: avc1SampleEntry(videoConfig)
|
|
@@ -22819,9 +22875,10 @@ ${this.lastInitStack}` : "";
|
|
|
22819
22875
|
);
|
|
22820
22876
|
}
|
|
22821
22877
|
if (audioConfig) {
|
|
22878
|
+
state.audioTrackId = traks.length + 1;
|
|
22822
22879
|
traks.push(
|
|
22823
22880
|
audioTrak({
|
|
22824
|
-
trackId:
|
|
22881
|
+
trackId: state.audioTrackId,
|
|
22825
22882
|
sampleRate: audioConfig.sampleRate,
|
|
22826
22883
|
channelCount: audioConfig.channelConfiguration,
|
|
22827
22884
|
sampleEntry: mp4aSampleEntry(audioConfig)
|
|
@@ -22832,8 +22889,8 @@ ${this.lastInitStack}` : "";
|
|
|
22832
22889
|
}
|
|
22833
22890
|
const fragments = [];
|
|
22834
22891
|
let duration = 0;
|
|
22835
|
-
if (videoConfig && videoNalus.length > 0) {
|
|
22836
|
-
const trackId =
|
|
22892
|
+
if (videoConfig && videoNalus.length > 0 && state.videoTrackId != null) {
|
|
22893
|
+
const trackId = state.videoTrackId;
|
|
22837
22894
|
const accessUnits = [];
|
|
22838
22895
|
let pendingParams = [];
|
|
22839
22896
|
for (const nalu of videoNalus) {
|
|
@@ -22900,8 +22957,8 @@ ${this.lastInitStack}` : "";
|
|
|
22900
22957
|
duration = accessUnits.length * frameDuration / MPEG_TIMESCALE;
|
|
22901
22958
|
}
|
|
22902
22959
|
}
|
|
22903
|
-
if (audioConfig && audioRawData && audioFrames.length > 0) {
|
|
22904
|
-
const trackId =
|
|
22960
|
+
if (audioConfig && audioRawData && audioFrames.length > 0 && state.audioTrackId != null) {
|
|
22961
|
+
const trackId = state.audioTrackId;
|
|
22905
22962
|
const samplesPerFrame = 1024;
|
|
22906
22963
|
const samples = [];
|
|
22907
22964
|
const parts = [];
|
|
@@ -23201,7 +23258,11 @@ ${this.lastInitStack}` : "";
|
|
|
23201
23258
|
async getSegment(time, affordance = 0) {
|
|
23202
23259
|
var _a3;
|
|
23203
23260
|
const playlist = await data2.getMediaPlaylist(playlistUri);
|
|
23204
|
-
const playlistBaseUrl =
|
|
23261
|
+
const playlistBaseUrl = getPlaylistBaseUrl(
|
|
23262
|
+
playlist,
|
|
23263
|
+
playlistUri,
|
|
23264
|
+
baseUrl
|
|
23265
|
+
);
|
|
23205
23266
|
const segments = buildSegmentTimeline(
|
|
23206
23267
|
deps,
|
|
23207
23268
|
playlistBaseUrl,
|
|
@@ -23248,9 +23309,13 @@ ${this.lastInitStack}` : "";
|
|
|
23248
23309
|
const variant2 = data2.mainPlaylist.variants[0];
|
|
23249
23310
|
const media = await data2.getMediaPlaylist(variant2.uri);
|
|
23250
23311
|
const contentDuration = media.ended ? media.segments.reduce((sum, s) => sum + s.duration, 0) : null;
|
|
23251
|
-
const playlistBaseUrl =
|
|
23312
|
+
const playlistBaseUrl = getPlaylistBaseUrl(media, variant2.uri, data2.baseUrl);
|
|
23252
23313
|
return discoverHlsInterstitials(media, playlistBaseUrl, contentDuration);
|
|
23253
23314
|
}
|
|
23315
|
+
function getPlaylistBaseUrl(playlist, playlistUri, mainBaseUrl) {
|
|
23316
|
+
var _a3;
|
|
23317
|
+
return (_a3 = playlist.baseUrl) != null ? _a3 : resolveUrl(playlistUri, mainBaseUrl);
|
|
23318
|
+
}
|
|
23254
23319
|
|
|
23255
23320
|
// src/track/hls/createDefaultHlsManifestTransformer.ts
|
|
23256
23321
|
function createDefaultHlsManifestTransformer(deps) {
|
|
@@ -23383,8 +23448,11 @@ ${this.lastInitStack}` : "";
|
|
|
23383
23448
|
const variantUrl = resolveUrl(uri, baseUrl);
|
|
23384
23449
|
const response = await requestWithRetry(variantUrl, requestInit, { abort });
|
|
23385
23450
|
const text = await readResponseBody(response, "text");
|
|
23386
|
-
const
|
|
23387
|
-
|
|
23451
|
+
const playlistUrl = response.url || variantUrl;
|
|
23452
|
+
const queryParams = parseQueryParams(playlistUrl);
|
|
23453
|
+
return __spreadProps(__spreadValues({}, parseMediaPlaylist(text, defines, queryParams)), {
|
|
23454
|
+
baseUrl: playlistUrl
|
|
23455
|
+
});
|
|
23388
23456
|
}
|
|
23389
23457
|
function parseQueryParams(url) {
|
|
23390
23458
|
const queryStart = url.indexOf("?");
|
|
@@ -23836,6 +23904,9 @@ ${this.lastInitStack}` : "";
|
|
|
23836
23904
|
for (const cachedTrack of this.trackCache.values()) {
|
|
23837
23905
|
cachedTrack.clearPrefetch();
|
|
23838
23906
|
}
|
|
23907
|
+
for (const adTracks of this.adTracksByParent.values()) {
|
|
23908
|
+
for (const adTrack of adTracks.values()) adTrack.clearPrefetch();
|
|
23909
|
+
}
|
|
23839
23910
|
}
|
|
23840
23911
|
clearQueue() {
|
|
23841
23912
|
this.setQueue(this._current, []);
|
|
@@ -27307,6 +27378,47 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
|
|
|
27307
27378
|
await flush();
|
|
27308
27379
|
expect(c.currentAdBreak).toBeNull();
|
|
27309
27380
|
});
|
|
27381
|
+
it("still enters a pending break when skipped while its ads resolve", async () => {
|
|
27382
|
+
var _a3;
|
|
27383
|
+
const c = createController();
|
|
27384
|
+
let resolveAds = () => void 0;
|
|
27385
|
+
const entered = [];
|
|
27386
|
+
await setContent(
|
|
27387
|
+
c,
|
|
27388
|
+
trackAds(
|
|
27389
|
+
makeBreak({
|
|
27390
|
+
id: "b1",
|
|
27391
|
+
startTime: 0,
|
|
27392
|
+
duration: 30,
|
|
27393
|
+
ads: () => new Promise((resolve) => {
|
|
27394
|
+
resolveAds = resolve;
|
|
27395
|
+
})
|
|
27396
|
+
}),
|
|
27397
|
+
makeBreak({
|
|
27398
|
+
id: "b2",
|
|
27399
|
+
startTime: 1,
|
|
27400
|
+
duration: 30,
|
|
27401
|
+
ads: [
|
|
27402
|
+
{
|
|
27403
|
+
id: "a2",
|
|
27404
|
+
startTime: 1,
|
|
27405
|
+
duration: 10,
|
|
27406
|
+
uri: "ad2.m3u8"
|
|
27407
|
+
}
|
|
27408
|
+
]
|
|
27409
|
+
})
|
|
27410
|
+
)
|
|
27411
|
+
);
|
|
27412
|
+
c.on("adBreakEntered", (e) => entered.push(e.adBreak.id));
|
|
27413
|
+
updateTime(2);
|
|
27414
|
+
await flush();
|
|
27415
|
+
expect(entered).toEqual(["b1"]);
|
|
27416
|
+
c.skipAdBreak();
|
|
27417
|
+
resolveAds([]);
|
|
27418
|
+
await flush();
|
|
27419
|
+
expect(entered).toEqual(["b1", "b2"]);
|
|
27420
|
+
expect((_a3 = c.currentAdBreak) == null ? void 0 : _a3.id).toBe("b2");
|
|
27421
|
+
});
|
|
27310
27422
|
});
|
|
27311
27423
|
describe("a break with no ads", () => {
|
|
27312
27424
|
it("completes immediately with a resume position and plays no ad", async () => {
|
|
@@ -27587,6 +27699,35 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
|
|
|
27587
27699
|
await flush();
|
|
27588
27700
|
expect(thirds).toEqual(["a1"]);
|
|
27589
27701
|
});
|
|
27702
|
+
it("dispatches each quartile at most once per ad", async () => {
|
|
27703
|
+
const c = createController();
|
|
27704
|
+
const events = [];
|
|
27705
|
+
c.on("adFirstQuartile", () => events.push("first"));
|
|
27706
|
+
c.on("adMidpoint", () => events.push("mid"));
|
|
27707
|
+
c.on("adThirdQuartile", () => events.push("third"));
|
|
27708
|
+
await setContent(
|
|
27709
|
+
c,
|
|
27710
|
+
trackAds(makeBreak({ startTime: 0, duration: 10 }))
|
|
27711
|
+
);
|
|
27712
|
+
updateTime(0);
|
|
27713
|
+
await flush();
|
|
27714
|
+
playbackController.dispatch("playing", {});
|
|
27715
|
+
playbackController.duration = 10;
|
|
27716
|
+
playbackController.playbackRate = 1;
|
|
27717
|
+
for (const [percent, time] of [
|
|
27718
|
+
[0.3, 3],
|
|
27719
|
+
[0.4, 4],
|
|
27720
|
+
[0.6, 6],
|
|
27721
|
+
[0.7, 7],
|
|
27722
|
+
[0.8, 8],
|
|
27723
|
+
[0.9, 9]
|
|
27724
|
+
]) {
|
|
27725
|
+
playbackController.currentTimePercent = percent;
|
|
27726
|
+
updateTime(time);
|
|
27727
|
+
await flush();
|
|
27728
|
+
}
|
|
27729
|
+
expect(events).toEqual(["first", "mid", "third"]);
|
|
27730
|
+
});
|
|
27590
27731
|
it("does not emit quartiles or throw when the ad duration is zero", async () => {
|
|
27591
27732
|
const c = createController();
|
|
27592
27733
|
const events = [];
|
|
@@ -28630,8 +28771,9 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
|
|
|
28630
28771
|
clientAttributes: {}
|
|
28631
28772
|
}, overrides);
|
|
28632
28773
|
}
|
|
28633
|
-
function okJsonResponse(body) {
|
|
28774
|
+
function okJsonResponse(body, url = "") {
|
|
28634
28775
|
return {
|
|
28776
|
+
url,
|
|
28635
28777
|
ok: true,
|
|
28636
28778
|
status: 200,
|
|
28637
28779
|
headers: { get: () => null },
|
|
@@ -28800,7 +28942,7 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
|
|
|
28800
28942
|
"https://example.com/ads.json"
|
|
28801
28943
|
);
|
|
28802
28944
|
expect(ads.length).toBe(2);
|
|
28803
|
-
expect(ads[0].uri).toBe("https://
|
|
28945
|
+
expect(ads[0].uri).toBe("https://example.com/mid1.m3u8");
|
|
28804
28946
|
expect(ads[0].duration).toBe(10);
|
|
28805
28947
|
expect(ads[1].uri).toBe("https://cdn.example.com/mid2.m3u8");
|
|
28806
28948
|
expect(ads[1].duration).toBeNull();
|
|
@@ -28808,6 +28950,33 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
|
|
|
28808
28950
|
globalThis.fetch = origFetch;
|
|
28809
28951
|
}
|
|
28810
28952
|
});
|
|
28953
|
+
it("resolves relative asset URIs against the redirected asset list URL", async () => {
|
|
28954
|
+
const origFetch = globalThis.fetch;
|
|
28955
|
+
const fetchSpy = jasmine.createSpy("fetch").and.resolveTo(
|
|
28956
|
+
okJsonResponse(
|
|
28957
|
+
{ ASSETS: [{ URI: "mid1.m3u8" }] },
|
|
28958
|
+
"https://ads.example.net/v2/ads.json"
|
|
28959
|
+
)
|
|
28960
|
+
);
|
|
28961
|
+
globalThis.fetch = fetchSpy;
|
|
28962
|
+
try {
|
|
28963
|
+
const playlist = makePlaylist({
|
|
28964
|
+
dateRanges: [
|
|
28965
|
+
makeRange({
|
|
28966
|
+
duration: 10,
|
|
28967
|
+
clientAttributes: {
|
|
28968
|
+
"X-ASSET-LIST": "https://example.com/redirected.json"
|
|
28969
|
+
}
|
|
28970
|
+
})
|
|
28971
|
+
]
|
|
28972
|
+
});
|
|
28973
|
+
const breaks = await discoverHlsInterstitials(playlist, BASE);
|
|
28974
|
+
const ads = await resolveValueProvider(breaks[0].ads);
|
|
28975
|
+
expect(ads[0].uri).toBe("https://ads.example.net/v2/mid1.m3u8");
|
|
28976
|
+
} finally {
|
|
28977
|
+
globalThis.fetch = origFetch;
|
|
28978
|
+
}
|
|
28979
|
+
});
|
|
28811
28980
|
it("caches the X-ASSET-LIST fetch across calls", async () => {
|
|
28812
28981
|
const origFetch = globalThis.fetch;
|
|
28813
28982
|
const fetchSpy = jasmine.createSpy("fetch").and.resolveTo(okJsonResponse({ ASSETS: [{ URI: "x.m3u8" }] }));
|
|
@@ -30185,10 +30354,10 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
|
|
|
30185
30354
|
});
|
|
30186
30355
|
});
|
|
30187
30356
|
describe("when created", () => {
|
|
30188
|
-
it("calls session.generateRequest() with the initData
|
|
30357
|
+
it("calls session.generateRequest() with the initData", () => {
|
|
30189
30358
|
expect(
|
|
30190
30359
|
mediaKeySession.generateRequest
|
|
30191
|
-
).toHaveBeenCalledOnceWith("cenc", initData
|
|
30360
|
+
).toHaveBeenCalledOnceWith("cenc", initData);
|
|
30192
30361
|
mediaKeySession.generateRequest.calls.reset();
|
|
30193
30362
|
const arrayBuffer = new ArrayBuffer(0);
|
|
30194
30363
|
standardCommonMediaKeySession = new StandardCommonMediaKeySession(
|
|
@@ -30201,6 +30370,21 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
|
|
|
30201
30370
|
mediaKeySession.generateRequest
|
|
30202
30371
|
).toHaveBeenCalledOnceWith("cenc", arrayBuffer);
|
|
30203
30372
|
});
|
|
30373
|
+
it("passes only the bytes an offset initData view spans", () => {
|
|
30374
|
+
mediaKeySession.generateRequest.calls.reset();
|
|
30375
|
+
const view = new Uint8Array([1, 2, 3, 4, 5]).subarray(1, 4);
|
|
30376
|
+
standardCommonMediaKeySession = new StandardCommonMediaKeySession(
|
|
30377
|
+
mediaKeySession,
|
|
30378
|
+
mimeType,
|
|
30379
|
+
"cenc",
|
|
30380
|
+
view
|
|
30381
|
+
);
|
|
30382
|
+
const [, passed] = mediaKeySession.generateRequest.calls.mostRecent().args;
|
|
30383
|
+
expectIterableEquals(
|
|
30384
|
+
new Uint8Array(bufferToArrayBuffer(passed)),
|
|
30385
|
+
[2, 3, 4]
|
|
30386
|
+
);
|
|
30387
|
+
});
|
|
30204
30388
|
describe("when session.generateRequest rejects", () => {
|
|
30205
30389
|
it("emits an error event", async () => {
|
|
30206
30390
|
mediaKeySession.generateRequest.and.rejectWith(
|
|
@@ -32658,6 +32842,13 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
|
|
|
32658
32842
|
).toBe("example0");
|
|
32659
32843
|
});
|
|
32660
32844
|
});
|
|
32845
|
+
describe("with an offset view", () => {
|
|
32846
|
+
it("reads only the bytes the view spans", () => {
|
|
32847
|
+
const padded = createContentIdByteArray("\0\0skd://example0\0\0");
|
|
32848
|
+
const view = padded.subarray(4, padded.byteLength - 4);
|
|
32849
|
+
expect(extractContentId(view)).toBe("example0");
|
|
32850
|
+
});
|
|
32851
|
+
});
|
|
32661
32852
|
describe("without match", () => {
|
|
32662
32853
|
it("throws ValidationError", () => {
|
|
32663
32854
|
expect(() => {
|
|
@@ -35951,6 +36142,24 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
|
|
|
35951
36142
|
expect(sourceBufferController.append).toHaveBeenCalledTimes(1);
|
|
35952
36143
|
});
|
|
35953
36144
|
});
|
|
36145
|
+
describe("when the append budget grows while a segment is partly appended", () => {
|
|
36146
|
+
it("appends only the bytes remaining in the segment", async () => {
|
|
36147
|
+
bufferingController.dispose();
|
|
36148
|
+
bufferingController = createBufferingController({
|
|
36149
|
+
maxAppendSize: { audio: 500 },
|
|
36150
|
+
minBuffer: 6
|
|
36151
|
+
});
|
|
36152
|
+
bufferingController.activate();
|
|
36153
|
+
setSegmentList([200, 400]);
|
|
36154
|
+
await open();
|
|
36155
|
+
await setTime(5);
|
|
36156
|
+
expect(getMostRecentAppendData().byteLength).toBe(300);
|
|
36157
|
+
sourceBufferController.append.calls.reset();
|
|
36158
|
+
await setTime(15.5);
|
|
36159
|
+
const appended = sourceBufferController.append.calls.allArgs().map(([data2]) => data2.byteLength);
|
|
36160
|
+
expect(appended[0]).toBe(100);
|
|
36161
|
+
});
|
|
36162
|
+
});
|
|
35954
36163
|
describe("when contentType is undefined", () => {
|
|
35955
36164
|
it("uses DEFAULT_MAX_APPEND_SIZE for max byte length", async () => {
|
|
35956
36165
|
setSegmentList(
|
|
@@ -36712,6 +36921,28 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
|
|
|
36712
36921
|
);
|
|
36713
36922
|
expect(() => controller.deactivate()).not.toThrow();
|
|
36714
36923
|
});
|
|
36924
|
+
it("does not report a re-activated media source as ready to append", async () => {
|
|
36925
|
+
open();
|
|
36926
|
+
await flushPromises();
|
|
36927
|
+
const firstRef = controller.createSourceBuffer("audio", "audio/mp4");
|
|
36928
|
+
expect(controller.readyToAppend).withContext("ready on the first media source").toBeTrue();
|
|
36929
|
+
firstRef.dispose();
|
|
36930
|
+
controller.deactivate();
|
|
36931
|
+
const secondSource = new MockMediaSource();
|
|
36932
|
+
implementEventFakes(secondSource);
|
|
36933
|
+
secondSource.addSourceBuffer.and.callFake(
|
|
36934
|
+
() => new MockSourceBuffer()
|
|
36935
|
+
);
|
|
36936
|
+
mediaSourceFactory.and.returnValue(secondSource);
|
|
36937
|
+
controller.activate();
|
|
36938
|
+
await flushPromises();
|
|
36939
|
+
controller.createSourceBuffer("audio", "audio/mp4");
|
|
36940
|
+
expect(controller.readyToAppend).withContext("duration not yet set on the new media source").toBeFalse();
|
|
36941
|
+
secondSource.readyState = "open";
|
|
36942
|
+
secondSource.dispatchEvent(mockEvent("sourceopen"));
|
|
36943
|
+
await flushPromises();
|
|
36944
|
+
expect(controller.readyToAppend).withContext("ready once the new duration is set").toBeTrue();
|
|
36945
|
+
});
|
|
36715
36946
|
});
|
|
36716
36947
|
describe("duration", () => {
|
|
36717
36948
|
it("sets media source duration after sourceopen", async () => {
|
|
@@ -38474,6 +38705,11 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
|
|
|
38474
38705
|
expect(drmProtectionValidator.isValid({ keySystem: 123 })).toBeFalse();
|
|
38475
38706
|
});
|
|
38476
38707
|
});
|
|
38708
|
+
describe("ALL_CONTENT_TYPES", () => {
|
|
38709
|
+
it("provides a comprehensive list of all content types", () => {
|
|
38710
|
+
expectTypeStrictlyEquals(true);
|
|
38711
|
+
});
|
|
38712
|
+
});
|
|
38477
38713
|
|
|
38478
38714
|
// test/unit/streaming/MediaTimeline.test.ts
|
|
38479
38715
|
describe("getMediaPeriodAtTime", () => {
|
|
@@ -41230,6 +41466,18 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
|
|
|
41230
41466
|
expect(result.length).toBe(1);
|
|
41231
41467
|
expect(result[0].language).toBe("es");
|
|
41232
41468
|
});
|
|
41469
|
+
it("discovers a text AdaptationSet by its Representation mimeType", () => {
|
|
41470
|
+
const m = manifest3(`
|
|
41471
|
+
<AdaptationSet lang="fr">
|
|
41472
|
+
<Representation id="fr-sub" mimeType="text/vtt" bandwidth="100">
|
|
41473
|
+
<BaseURL>fr.vtt</BaseURL>
|
|
41474
|
+
</Representation>
|
|
41475
|
+
</AdaptationSet>`);
|
|
41476
|
+
const result = discoverDashTextTracks(m, baseUrl);
|
|
41477
|
+
expect(result.length).toBe(1);
|
|
41478
|
+
expect(result[0].language).toBe("fr");
|
|
41479
|
+
expect(result[0].uri).toBe("https://example.com/dash/fr.vtt");
|
|
41480
|
+
});
|
|
41233
41481
|
it("classifies kind=captions when role=caption is set", () => {
|
|
41234
41482
|
const m = manifest3(`
|
|
41235
41483
|
<AdaptationSet contentType="text" lang="en" mimeType="text/vtt">
|
|
@@ -41284,6 +41532,10 @@ ${(_a3 = this.failedResult.failedExpectations[0]) == null ? void 0 : _a3.message
|
|
|
41284
41532
|
</AdaptationSet>`);
|
|
41285
41533
|
expect(discoverDashTextTracks(m, baseUrl)).toEqual([]);
|
|
41286
41534
|
});
|
|
41535
|
+
it("skips a non-text AdaptationSet with no Representation", () => {
|
|
41536
|
+
const m = manifest3(`<AdaptationSet contentType="audio"/>`);
|
|
41537
|
+
expect(discoverDashTextTracks(m, baseUrl)).toEqual([]);
|
|
41538
|
+
});
|
|
41287
41539
|
it("skips text AdaptationSets carrying segmented codecs (stpp/wvtt)", () => {
|
|
41288
41540
|
const m = manifest3(`
|
|
41289
41541
|
<AdaptationSet contentType="text" mimeType="application/mp4" codecs="stpp">
|
|
@@ -42315,6 +42567,29 @@ hi`;
|
|
|
42315
42567
|
expect(cues.length).toBe(1);
|
|
42316
42568
|
expect(cues[0].text).toBe("hi");
|
|
42317
42569
|
});
|
|
42570
|
+
it("parses a cue that follows the signature with no blank line", () => {
|
|
42571
|
+
const text = `WEBVTT
|
|
42572
|
+
00:00:01.000 --> 00:00:02.000
|
|
42573
|
+
hi
|
|
42574
|
+
|
|
42575
|
+
00:00:03.000 --> 00:00:04.000
|
|
42576
|
+
there`;
|
|
42577
|
+
const cues = parseWebVtt(text).cues;
|
|
42578
|
+
expect(cues.length).toBe(2);
|
|
42579
|
+
expect(cues[0].startTime).toBe(1);
|
|
42580
|
+
expect(cues[0].text).toBe("hi");
|
|
42581
|
+
expect(cues[1].text).toBe("there");
|
|
42582
|
+
});
|
|
42583
|
+
it("keeps header lines as header when a cue follows with no blank line", () => {
|
|
42584
|
+
const text = `WEBVTT
|
|
42585
|
+
Kind: captions
|
|
42586
|
+
00:00:01.000 --> 00:00:02.000
|
|
42587
|
+
hi`;
|
|
42588
|
+
const cues = parseWebVtt(text).cues;
|
|
42589
|
+
expect(cues.length).toBe(1);
|
|
42590
|
+
expect(cues[0].id).toBeNull();
|
|
42591
|
+
expect(cues[0].text).toBe("hi");
|
|
42592
|
+
});
|
|
42318
42593
|
it("handles trailing identifier without timing line", () => {
|
|
42319
42594
|
const text = `WEBVTT
|
|
42320
42595
|
|
|
@@ -43704,6 +43979,13 @@ x`);
|
|
|
43704
43979
|
});
|
|
43705
43980
|
});
|
|
43706
43981
|
|
|
43982
|
+
// test/unit/text/TextTrack.test.ts
|
|
43983
|
+
describe("ALL_TEXT_TRACK_EVENTS", () => {
|
|
43984
|
+
it("provides a comprehensive list of all text track events", () => {
|
|
43985
|
+
expectTypeStrictlyEquals(true);
|
|
43986
|
+
});
|
|
43987
|
+
});
|
|
43988
|
+
|
|
43707
43989
|
// test/unit/text/VttCueStyle.test.ts
|
|
43708
43990
|
describe("VttCueStyle", () => {
|
|
43709
43991
|
describe("isVttCue", () => {
|
|
@@ -48810,6 +49092,29 @@ x`);
|
|
|
48810
49092
|
);
|
|
48811
49093
|
fetchSpy.and.callThrough();
|
|
48812
49094
|
});
|
|
49095
|
+
it("resolves segment and map URIs against the media playlist baseUrl", async () => {
|
|
49096
|
+
const variant2 = createVariant("v1.m3u8", 128e3);
|
|
49097
|
+
const playlist = __spreadProps(__spreadValues({}, createMediaPlaylist([10])), {
|
|
49098
|
+
// The media playlist was redirected away from the main playlist's
|
|
49099
|
+
// directory.
|
|
49100
|
+
baseUrl: "https://redirect.example.net/hls/v1.m3u8"
|
|
49101
|
+
});
|
|
49102
|
+
const manifestData2 = createManifestData([variant2], playlist);
|
|
49103
|
+
const fetchSpy = spyOn(globalThis, "fetch").and.callFake(
|
|
49104
|
+
() => Promise.resolve(new Response(new ArrayBuffer(100)))
|
|
49105
|
+
);
|
|
49106
|
+
const timeline = buildHlsMediaTimeline(deps, manifestData2);
|
|
49107
|
+
const quality = timeline.periods[0].qualities[0];
|
|
49108
|
+
const segment = await quality.getSegment(5);
|
|
49109
|
+
await segment.initData();
|
|
49110
|
+
await segment.data();
|
|
49111
|
+
const urls = fetchSpy.calls.allArgs().map(([input]) => String(input));
|
|
49112
|
+
expect(urls).toEqual([
|
|
49113
|
+
"https://redirect.example.net/hls/init.mp4",
|
|
49114
|
+
"https://redirect.example.net/hls/seg0.m4s"
|
|
49115
|
+
]);
|
|
49116
|
+
fetchSpy.and.callThrough();
|
|
49117
|
+
});
|
|
48813
49118
|
it("getDuration throws when no variants", async () => {
|
|
48814
49119
|
const manifestData2 = createManifestData([], createMediaPlaylist([]));
|
|
48815
49120
|
const timeline = buildHlsMediaTimeline(deps, manifestData2);
|
|
@@ -49487,6 +49792,29 @@ x`);
|
|
|
49487
49792
|
"https://example.com/path/audio.m3u8"
|
|
49488
49793
|
);
|
|
49489
49794
|
});
|
|
49795
|
+
it("sets the baseUrl from the response URL", async () => {
|
|
49796
|
+
mockRequester.request.and.callFake(() => {
|
|
49797
|
+
const resp = new Response(mediaM3u8);
|
|
49798
|
+
Object.defineProperty(resp, "url", {
|
|
49799
|
+
value: "https://redirected.com/hls/audio.m3u8"
|
|
49800
|
+
});
|
|
49801
|
+
return Promise.resolve(resp);
|
|
49802
|
+
});
|
|
49803
|
+
const playlist = await fetchMediaPlaylist({
|
|
49804
|
+
uri: "audio.m3u8",
|
|
49805
|
+
baseUrl: "https://example.com/path/main.m3u8",
|
|
49806
|
+
defines: void 0
|
|
49807
|
+
});
|
|
49808
|
+
expect(playlist.baseUrl).toBe("https://redirected.com/hls/audio.m3u8");
|
|
49809
|
+
});
|
|
49810
|
+
it("falls back to the requested URL when the response has no URL", async () => {
|
|
49811
|
+
const playlist = await fetchMediaPlaylist({
|
|
49812
|
+
uri: "audio.m3u8",
|
|
49813
|
+
baseUrl: "https://example.com/path/main.m3u8",
|
|
49814
|
+
defines: void 0
|
|
49815
|
+
});
|
|
49816
|
+
expect(playlist.baseUrl).toBe("https://example.com/path/audio.m3u8");
|
|
49817
|
+
});
|
|
49490
49818
|
it("resolves EXT-X-DEFINE:QUERYPARAM from the playlist URL query string", async () => {
|
|
49491
49819
|
mockRequester.request.and.callFake(
|
|
49492
49820
|
() => Promise.resolve(
|
|
@@ -52120,49 +52448,6 @@ x`);
|
|
|
52120
52448
|
expect(track2.clearPrefetch).toHaveBeenCalledTimes(1);
|
|
52121
52449
|
}
|
|
52122
52450
|
});
|
|
52123
|
-
it("also clears prefetch on preloaded ad tracks", async () => {
|
|
52124
|
-
pending(
|
|
52125
|
-
"REVIEW: the refactor no longer proactively preloads ad tracks discovered on the current track (ad tracks are created on adEntered only). Decide: intended removal (delete this spec) or regression (restore discovery-time ad preloading)."
|
|
52126
|
-
);
|
|
52127
|
-
const [main] = createLoadOptionsList(1);
|
|
52128
|
-
trackController.load(main);
|
|
52129
|
-
const track2 = trackController.activeTrack;
|
|
52130
|
-
const ads = {
|
|
52131
|
-
trackUri: main.uri,
|
|
52132
|
-
adBreaks: [
|
|
52133
|
-
{
|
|
52134
|
-
id: "b1",
|
|
52135
|
-
startTime: 5,
|
|
52136
|
-
duration: 10,
|
|
52137
|
-
placement: "midroll",
|
|
52138
|
-
restrict: {},
|
|
52139
|
-
once: false,
|
|
52140
|
-
resumeOffset: null,
|
|
52141
|
-
playoutLimit: null,
|
|
52142
|
-
resolutionTimeOffset: null,
|
|
52143
|
-
skipControl: () => null,
|
|
52144
|
-
ads: () => Promise.resolve([
|
|
52145
|
-
{
|
|
52146
|
-
id: "a1",
|
|
52147
|
-
startTime: 5,
|
|
52148
|
-
duration: 10,
|
|
52149
|
-
uri: "https://ads/a.m3u8"
|
|
52150
|
-
}
|
|
52151
|
-
])
|
|
52152
|
-
}
|
|
52153
|
-
]
|
|
52154
|
-
};
|
|
52155
|
-
track2.ads = ads;
|
|
52156
|
-
track2.dispatch("adsChange", { previous: null, current: ads });
|
|
52157
|
-
await Promise.resolve();
|
|
52158
|
-
await Promise.resolve();
|
|
52159
|
-
await Promise.resolve();
|
|
52160
|
-
const adTrack = trackController.getCachedTrack(
|
|
52161
|
-
"https://ads/a.m3u8"
|
|
52162
|
-
);
|
|
52163
|
-
trackController.clearPrefetch();
|
|
52164
|
-
expect(adTrack.clearPrefetch).toHaveBeenCalled();
|
|
52165
|
-
});
|
|
52166
52451
|
});
|
|
52167
52452
|
describe("clearQueue", () => {
|
|
52168
52453
|
it("clears the queue without unloading the current track", async () => {
|
|
@@ -52667,6 +52952,19 @@ x`);
|
|
|
52667
52952
|
expect(adTrack).withContext("midroll ad track warmed").toBeDefined();
|
|
52668
52953
|
expect(adTrack.preload).toHaveBeenCalled();
|
|
52669
52954
|
});
|
|
52955
|
+
it("clears prefetch on a preloaded ad track", async () => {
|
|
52956
|
+
const [main] = createLoadOptionsList(1);
|
|
52957
|
+
factoryGivingBreak(main.uri, []);
|
|
52958
|
+
trackController.load(main);
|
|
52959
|
+
await flushAds();
|
|
52960
|
+
deps.adController.dispatch("adPreload", {
|
|
52961
|
+
adBreak: midrollBreak("https://ads/mid.m3u8")
|
|
52962
|
+
});
|
|
52963
|
+
await flushAds();
|
|
52964
|
+
const adTrack = created.get("https://ads/mid.m3u8");
|
|
52965
|
+
trackController.clearPrefetch();
|
|
52966
|
+
expect(adTrack.clearPrefetch).toHaveBeenCalledTimes(1);
|
|
52967
|
+
});
|
|
52670
52968
|
it("ignores adPreload when there is no parent track", () => {
|
|
52671
52969
|
expect(
|
|
52672
52970
|
() => deps.adController.dispatch("adPreload", {
|
|
@@ -52862,21 +53160,6 @@ x`);
|
|
|
52862
53160
|
objectContaining23({ startTime: 3 })
|
|
52863
53161
|
);
|
|
52864
53162
|
});
|
|
52865
|
-
it("skips the deferred resume if interrupted before the frame", async () => {
|
|
52866
|
-
pending(
|
|
52867
|
-
"REVIEW: content resume on adBreakCompleted is now synchronous (no deferred/interruptible frame), so this interruption guard no longer applies. Decide: intended or restore deferral."
|
|
52868
|
-
);
|
|
52869
|
-
const [main] = createLoadOptionsList(1);
|
|
52870
|
-
trackController.load(main);
|
|
52871
|
-
const changeSpy = createEventSpy(trackController, "trackActivated");
|
|
52872
|
-
deps.adController.dispatch("adBreakCompleted", {
|
|
52873
|
-
adBreak: adBreak("midroll"),
|
|
52874
|
-
resumePosition: 5
|
|
52875
|
-
});
|
|
52876
|
-
deps.adController.currentAd = __spreadProps(__spreadValues({}, ad), { id: "other" });
|
|
52877
|
-
await clock.tick();
|
|
52878
|
-
expect(changeSpy).not.toHaveBeenCalled();
|
|
52879
|
-
});
|
|
52880
53163
|
it("advances to the next track after a postroll ad when one exists", async () => {
|
|
52881
53164
|
var _a3;
|
|
52882
53165
|
const list = createLoadOptionsList(2);
|
|
@@ -55810,13 +56093,15 @@ x`);
|
|
|
55810
56093
|
await expectTrackCanSeekTo(player, 5);
|
|
55811
56094
|
});
|
|
55812
56095
|
it("can continue seeking", async () => {
|
|
55813
|
-
|
|
56096
|
+
let nextEnded = nextEventAsPromise(player, "ended");
|
|
55814
56097
|
await expectTrackCanSeekTo(player, 999);
|
|
55815
56098
|
await nextEnded;
|
|
55816
56099
|
await expectTrackCanSeekTo(player, 0);
|
|
55817
56100
|
await expectTrackCanSeekTo(player, 5);
|
|
55818
56101
|
await expectTrackCanSeekTo(player, 15);
|
|
55819
56102
|
await expectTrackCanSeekTo(player, 35);
|
|
56103
|
+
await player.play();
|
|
56104
|
+
nextEnded = nextEventAsPromise(player, "ended");
|
|
55820
56105
|
await expectTrackCanSeekTo(player, 999);
|
|
55821
56106
|
await nextEnded;
|
|
55822
56107
|
});
|