@amazon/vinyl 3.2.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +30 -24
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +30 -24
- package/dist/index.js.map +2 -2
- package/dist/test/integ.es5.js +167 -155
- package/dist/test/integ.js +260 -50
- package/dist/test/integ.js.map +2 -2
- package/dist/types/current/ad/AdControllerImpl.d.ts +18 -2
- package/dist/types/current/ad/AdControllerImpl.d.ts.map +1 -1
- package/dist/types/current/ad/AdControllerImpl.js +42 -20
- package/dist/types/current/playback/createStallMonitor.d.ts.map +1 -1
- package/dist/types/current/playback/createStallMonitor.js +19 -14
- package/dist/types/current/tsconfig.tsbuildinfo +1 -1
- package/dist/types/ts3.7/ad/AdControllerImpl.d.ts +18 -2
- package/dist/types/ts4.1/ad/AdControllerImpl.d.ts +18 -2
- package/dist/types/ts4.7/ad/AdControllerImpl.d.ts +18 -2
- package/dist/unit/types/current/ad/AdControllerImpl.test.js +110 -4
- package/dist/unit/types/current/playback/createStallMonitor.test.js +38 -0
- package/dist/unit/types/current/tsconfig.tsbuildinfo +1 -1
- package/dist/vinylTestUtil/index.js +10 -1
- package/dist/vinylTestUtil/index.js.map +2 -2
- package/dist/vinylTestUtil/types/current/assets/vinylTestAssets.d.ts +5 -0
- package/dist/vinylTestUtil/types/current/assets/vinylTestAssets.d.ts.map +1 -1
- package/dist/vinylTestUtil/types/current/assets/vinylTestAssets.js +9 -0
- package/dist/vinylTestUtil/types/current/tsconfig.tsbuildinfo +1 -1
- package/dist/vinylTestUtil/types/ts3.7/assets/vinylTestAssets.d.ts +5 -0
- package/dist/vinylTestUtil/types/ts4.1/assets/vinylTestAssets.d.ts +5 -0
- package/dist/vinylTestUtil/types/ts4.7/assets/vinylTestAssets.d.ts +5 -0
- package/package.json +10 -10
|
@@ -7,6 +7,15 @@ import type { AdsProvider } from './AdsProvider';
|
|
|
7
7
|
* The % playhead start tolerance for playback progress when emitting ad progress events.
|
|
8
8
|
*/
|
|
9
9
|
export declare const AD_START_TOLERANCE = 0.05;
|
|
10
|
+
/**
|
|
11
|
+
* When a break's X-PLAYOUT-LIMIT budget is reached, an ad whose real media end is
|
|
12
|
+
* within this many seconds is allowed to finish on its own `ended` rather than
|
|
13
|
+
* being cut. The limit is a coarse, often whole-second budget while the media's
|
|
14
|
+
* true length is fractional, so without this grace an ad effectively as long as
|
|
15
|
+
* its budget would be clipped a fraction short. The tolerance is measured against
|
|
16
|
+
* the playback-reported (media) duration, not the ad's declared duration.
|
|
17
|
+
*/
|
|
18
|
+
export declare const PLAYOUT_LIMIT_TOLERANCE = 1;
|
|
10
19
|
export interface AdControllerImplDeps {
|
|
11
20
|
readonly playbackController: ReadonlyPlaybackController;
|
|
12
21
|
}
|
|
@@ -129,8 +138,15 @@ export declare class AdControllerImpl extends EventHostImpl<AdEventMap> implemen
|
|
|
129
138
|
private emitAdProgressEvents;
|
|
130
139
|
private emitTimeUpdate;
|
|
131
140
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
141
|
+
* Enforces the break-level playout limit (X-PLAYOUT-LIMIT): a budget shared
|
|
142
|
+
* across all of the break's ads. When cumulative playout reaches it, the
|
|
143
|
+
* whole break ends, dropping any ads that have not started.
|
|
144
|
+
*
|
|
145
|
+
* This is deliberately NOT a per-ad cap. Each ad asset is its own source and
|
|
146
|
+
* ends on its media `ended` (see the 'ended' handler), which is what advances
|
|
147
|
+
* a multi-ad break. Ending an ad at its declared per-ad DURATION instead would
|
|
148
|
+
* truncate the real asset whenever a packager under-declares it — e.g. rounds
|
|
149
|
+
* a 6.732s asset down to a whole-second 6 — cutting off the fractional tail.
|
|
134
150
|
*/
|
|
135
151
|
private enforcePlayoutLimits;
|
|
136
152
|
private setPendingBreaks;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdControllerImpl.d.ts","sourceRoot":"","sources":["../../../../src/ad/AdControllerImpl.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"AdControllerImpl.d.ts","sourceRoot":"","sources":["../../../../src/ad/AdControllerImpl.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,15 @@ import { AdError } from './AdError';
|
|
|
8
8
|
* The % playhead start tolerance for playback progress when emitting ad progress events.
|
|
9
9
|
*/
|
|
10
10
|
export const AD_START_TOLERANCE = 0.05;
|
|
11
|
+
/**
|
|
12
|
+
* When a break's X-PLAYOUT-LIMIT budget is reached, an ad whose real media end is
|
|
13
|
+
* within this many seconds is allowed to finish on its own `ended` rather than
|
|
14
|
+
* being cut. The limit is a coarse, often whole-second budget while the media's
|
|
15
|
+
* true length is fractional, so without this grace an ad effectively as long as
|
|
16
|
+
* its budget would be clipped a fraction short. The tolerance is measured against
|
|
17
|
+
* the playback-reported (media) duration, not the ad's declared duration.
|
|
18
|
+
*/
|
|
19
|
+
export const PLAYOUT_LIMIT_TOLERANCE = 1;
|
|
11
20
|
export const defaultAdControllerImplOptions = {
|
|
12
21
|
adLoadTimeout: 15,
|
|
13
22
|
preloadAheadTime: 10,
|
|
@@ -560,30 +569,43 @@ export class AdControllerImpl extends EventHostImpl {
|
|
|
560
569
|
});
|
|
561
570
|
}
|
|
562
571
|
/**
|
|
563
|
-
*
|
|
564
|
-
*
|
|
572
|
+
* Enforces the break-level playout limit (X-PLAYOUT-LIMIT): a budget shared
|
|
573
|
+
* across all of the break's ads. When cumulative playout reaches it, the
|
|
574
|
+
* whole break ends, dropping any ads that have not started.
|
|
575
|
+
*
|
|
576
|
+
* This is deliberately NOT a per-ad cap. Each ad asset is its own source and
|
|
577
|
+
* ends on its media `ended` (see the 'ended' handler), which is what advances
|
|
578
|
+
* a multi-ad break. Ending an ad at its declared per-ad DURATION instead would
|
|
579
|
+
* truncate the real asset whenever a packager under-declares it — e.g. rounds
|
|
580
|
+
* a 6.732s asset down to a whole-second 6 — cutting off the fractional tail.
|
|
565
581
|
*/
|
|
566
582
|
enforcePlayoutLimits(adState) {
|
|
583
|
+
if (!adState.started)
|
|
584
|
+
return;
|
|
585
|
+
const { parentBreak } = adState;
|
|
586
|
+
// Enforce independent of a finite content duration so live ads with a
|
|
587
|
+
// declared playout limit are still bounded.
|
|
588
|
+
const limit = parentBreak.adBreak.playoutLimit;
|
|
589
|
+
if (limit == null)
|
|
590
|
+
return;
|
|
567
591
|
const pC = this.deps.playbackController;
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
if
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
this.endAd(adState);
|
|
581
|
-
}
|
|
582
|
-
else if (ad.duration != null && elapsed >= ad.duration) {
|
|
583
|
-
// This ad reached its declared duration: advance to the next.
|
|
584
|
-
this.endAd(adState);
|
|
585
|
-
}
|
|
592
|
+
const elapsed = Math.max(0, pC.currentTime - adState.timeStart);
|
|
593
|
+
if (parentBreak.playoutElapsed + elapsed < limit)
|
|
594
|
+
return;
|
|
595
|
+
// Budget reached — but if the current ad is essentially at its natural
|
|
596
|
+
// media end (within PLAYOUT_LIMIT_TOLERANCE of the playback-reported
|
|
597
|
+
// duration), let it finish on its own `ended` rather than clipping the
|
|
598
|
+
// tail. A known finite, positive duration is required; an unknown (0) or
|
|
599
|
+
// non-finite duration (e.g. live) enforces the limit strictly.
|
|
600
|
+
if (isFinite(pC.duration) &&
|
|
601
|
+
pC.duration > 0 &&
|
|
602
|
+
pC.duration - pC.currentTime <= PLAYOUT_LIMIT_TOLERANCE) {
|
|
603
|
+
return;
|
|
586
604
|
}
|
|
605
|
+
// The break's total playout limit is reached: end the whole break,
|
|
606
|
+
// dropping any ads that have not started.
|
|
607
|
+
parentBreak.clear();
|
|
608
|
+
this.endAd(adState);
|
|
587
609
|
}
|
|
588
610
|
setPendingBreaks(newPending) {
|
|
589
611
|
this.pendingAdBreaks = newPending.filter((adBreak) => !this.isBreakSuppressed(adBreak));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createStallMonitor.d.ts","sourceRoot":"","sources":["../../../../src/playback/createStallMonitor.ts"],"names":[],"mappings":"AAKA,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAA;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAE/D,MAAM,WAAW,mBAAmB;IAChC;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAEhC;;OAEG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CACjC;AAED,MAAM,WAAW,cAAc;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,2BAA2B;IAC3B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;CACpC;AAED,MAAM,WAAW,qBAAqB;IAClC,6CAA6C;IAC7C,QAAQ,CAAC,cAAc,EAAE,MAAM,IAAI,CAAA;IACnC,yCAAyC;IACzC,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAA;CACxD;
|
|
1
|
+
{"version":3,"file":"createStallMonitor.d.ts","sourceRoot":"","sources":["../../../../src/playback/createStallMonitor.ts"],"names":[],"mappings":"AAKA,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAA;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAE/D,MAAM,WAAW,mBAAmB;IAChC;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAEhC;;OAEG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CACjC;AAED,MAAM,WAAW,cAAc;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,2BAA2B;IAC3B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;CACpC;AAED,MAAM,WAAW,qBAAqB;IAClC,6CAA6C;IAC7C,QAAQ,CAAC,cAAc,EAAE,MAAM,IAAI,CAAA;IACnC,yCAAyC;IACzC,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAA;CACxD;AASD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAC9B,UAAU,EAAE,0BAA0B,EACtC,SAAS,EAAE,qBAAqB,EAChC,OAAO,GAAE,mBAAwB,GAClC,MAAM,IAAI,CA+EZ"}
|
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { createDisposer } from '@amazon/vinyl-util';
|
|
6
6
|
import { StallEndedReason } from './ReadonlyPlaybackController';
|
|
7
|
+
/**
|
|
8
|
+
* Minimum forward `currentTime` change (seconds) that counts as real progress. Guards the
|
|
9
|
+
* progress check against floating-point jitter so a negligible advance isn't mistaken for the
|
|
10
|
+
* play head moving.
|
|
11
|
+
*/
|
|
12
|
+
const PROGRESS_EPSILON = 1e-6;
|
|
7
13
|
/**
|
|
8
14
|
* Watches a {@link ReadonlyPlaybackController} for stalls while playing: the play head freezing
|
|
9
15
|
* (no `timeUpdate`) for longer than {@link StallMonitorOptions.stallThreshold} seconds.
|
|
@@ -26,6 +32,7 @@ export function createStallMonitor(controller, callbacks, options = {}) {
|
|
|
26
32
|
let lastProgressAt = Date.now();
|
|
27
33
|
let inStall = false;
|
|
28
34
|
let pollId = null;
|
|
35
|
+
const { add, dispose } = createDisposer();
|
|
29
36
|
const endStall = (reason) => {
|
|
30
37
|
if (!inStall)
|
|
31
38
|
return;
|
|
@@ -44,6 +51,7 @@ export function createStallMonitor(controller, callbacks, options = {}) {
|
|
|
44
51
|
clearInterval(pollId);
|
|
45
52
|
pollId = null;
|
|
46
53
|
};
|
|
54
|
+
add(stopPoll);
|
|
47
55
|
const startPoll = () => {
|
|
48
56
|
if (pollId != null)
|
|
49
57
|
return;
|
|
@@ -63,18 +71,22 @@ export function createStallMonitor(controller, callbacks, options = {}) {
|
|
|
63
71
|
observedPlaying = false;
|
|
64
72
|
stopPoll();
|
|
65
73
|
};
|
|
66
|
-
const { add, dispose } = createDisposer();
|
|
67
74
|
add(controller.on('playing', () => {
|
|
68
|
-
// Resuming from a stall closes it
|
|
69
|
-
// begin the freeze clock now (no `timeUpdate` has necessarily arrived yet).
|
|
75
|
+
// Resuming from a stall closes it (using the pre-resume freeze start for its duration).
|
|
70
76
|
if (inStall)
|
|
71
77
|
endStall(StallEndedReason.PLAYING);
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
// Whether resuming or freshly starting, the play head is advancing again, so restart the
|
|
79
|
+
// freeze clock. Without this the poll could immediately re-detect a stall from the stale
|
|
80
|
+
// pre-freeze timestamp before the first post-resume `timeUpdate` resets it.
|
|
81
|
+
lastProgressAt = Date.now();
|
|
74
82
|
observedPlaying = true;
|
|
75
83
|
startPoll();
|
|
76
84
|
}));
|
|
77
|
-
add(controller.on('timeUpdate', () => {
|
|
85
|
+
add(controller.on('timeUpdate', ({ previous, current }) => {
|
|
86
|
+
// Browsers emit `timeUpdate` while frozen (unchanged/backward `currentTime`); only a
|
|
87
|
+
// forward advance is progress, else a stall is ended and re-detected, doubling events.
|
|
88
|
+
if (previous != null && current - previous <= PROGRESS_EPSILON)
|
|
89
|
+
return;
|
|
78
90
|
// The play head advanced: close any open stall, then reset the freeze clock.
|
|
79
91
|
if (inStall)
|
|
80
92
|
endStall(StallEndedReason.PLAYING);
|
|
@@ -83,12 +95,5 @@ export function createStallMonitor(controller, callbacks, options = {}) {
|
|
|
83
95
|
add(controller.on('pause', () => suspend(StallEndedReason.PAUSE)));
|
|
84
96
|
add(controller.on('seeking', () => suspend(StallEndedReason.SEEKING)));
|
|
85
97
|
add(controller.on('emptied', () => suspend(StallEndedReason.EMPTIED)));
|
|
86
|
-
|
|
87
|
-
return () => {
|
|
88
|
-
if (stopped)
|
|
89
|
-
return;
|
|
90
|
-
stopped = true;
|
|
91
|
-
stopPoll();
|
|
92
|
-
dispose();
|
|
93
|
-
};
|
|
98
|
+
return dispose;
|
|
94
99
|
}
|