@dolby-optiview/ads-sdk-core 1.2.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/OptiViewAds.d.ts +5 -4
- package/dist/OptiViewAds.js +1 -1
- package/dist/OptiViewAdsExternalVendors.d.ts +32 -0
- package/dist/external-playback/index.d.ts +4 -0
- package/dist/external-playback/index.js +1 -0
- package/dist/external-playback/observeExternalPlayback.d.ts +19 -0
- package/dist/external-playback/observeExternalPlayback.js +1 -0
- package/dist/external-playback/reconnectHold.d.ts +19 -0
- package/dist/external-playback/reconnectHold.js +1 -0
- package/dist/generated/diagnosticCodes.d.ts +46 -6
- package/dist/generated/diagnosticCodes.js +1 -1
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/index.d.ts +7 -5
- package/dist/index.js +1 -1
- package/dist/interfaces/AdSourceQueue.d.ts +19 -0
- package/dist/interfaces/AdSourceQueue.js +1 -0
- package/dist/interfaces/PlayerAdapter.d.ts +31 -1
- package/dist/internal/index.d.ts +2 -0
- package/dist/internal/index.js +1 -1
- package/dist/services/AdBreakSequencer.d.ts +33 -4
- package/dist/services/AdBreakSequencer.js +1 -1
- package/dist/services/AdPlayerController.d.ts +12 -73
- package/dist/services/AdPlayerController.js +1 -1
- package/dist/services/BreakChain.d.ts +43 -0
- package/dist/services/BreakChain.js +1 -0
- package/dist/services/BreakChainRecorder.d.ts +63 -0
- package/dist/services/BreakChainRecorder.js +1 -0
- package/dist/services/BreakPreloadLedger.d.ts +13 -0
- package/dist/services/BreakPreloadLedger.js +1 -0
- package/dist/services/BreakScheduler.d.ts +20 -6
- package/dist/services/BreakScheduler.js +1 -1
- package/dist/services/BreakTransitionTimer.d.ts +27 -2
- package/dist/services/BreakTransitionTimer.js +1 -1
- package/dist/services/CmcdAdReporter.d.ts +1 -0
- package/dist/services/CmcdAdReporter.js +1 -1
- package/dist/services/ExternalPlaybackGate.d.ts +40 -0
- package/dist/services/ExternalPlaybackGate.js +1 -0
- package/dist/services/LiveStartPushbackController.d.ts +5 -10
- package/dist/services/LiveStartPushbackController.js +1 -1
- package/dist/services/ManifestService.d.ts +2 -1
- package/dist/services/ManifestService.js +1 -1
- package/dist/services/ReloadGuard.d.ts +11 -0
- package/dist/services/ReloadGuard.js +1 -0
- package/dist/services/RewindRearm.d.ts +3 -1
- package/dist/services/RewindRearm.js +1 -1
- package/dist/services/SsaiController.js +1 -1
- package/dist/services/adPlayer/AdPlayerCallbacks.d.ts +63 -0
- package/dist/services/adPlayer/AdPlayerCallbacks.js +1 -0
- package/dist/services/adPlayer/AdPlayerEvents.d.ts +3 -7
- package/dist/services/adPlayer/AdPlayerEvents.js +1 -1
- package/dist/services/adPlayer/AdPlayerState.d.ts +0 -1
- package/dist/services/adPlayer/AdPlayerState.js +1 -1
- package/dist/services/adPlayer/AdPreloader.d.ts +2 -2
- package/dist/services/adPlayer/AdPreloader.js +1 -1
- package/dist/services/adPlayer/AdStage.d.ts +7 -4
- package/dist/services/adPlayer/AdStage.js +1 -1
- package/dist/services/adPlayer/AssetParameterResolver.d.ts +10 -2
- package/dist/services/adPlayer/AssetParameterResolver.js +1 -1
- package/dist/services/adPlayer/AssetPlayback.d.ts +9 -2
- package/dist/services/adPlayer/AssetPlayback.js +1 -1
- package/dist/services/adPlayer/AudioController.d.ts +58 -0
- package/dist/services/adPlayer/AudioController.js +1 -0
- package/dist/services/adPlayer/BreakSequenceDriver.d.ts +9 -3
- package/dist/services/adPlayer/BreakSequenceDriver.js +1 -1
- package/dist/services/adPlayer/ContentResumeCoordinator.d.ts +2 -0
- package/dist/services/adPlayer/ContentResumeCoordinator.js +1 -1
- package/dist/services/adPlayer/GamPodBridge.d.ts +11 -1
- package/dist/services/adPlayer/GamPodBridge.js +1 -1
- package/dist/services/adPlayer/PauseAdPresenter.d.ts +3 -1
- package/dist/services/adPlayer/PauseAdPresenter.js +1 -1
- package/dist/services/adPlayer/PreparedPresentation.js +1 -1
- package/dist/services/adPlayer/PresentationModeTracker.d.ts +1 -1
- package/dist/services/adPlayer/PresentationModeTracker.js +1 -1
- package/dist/services/adPlayer/SharedElementBreakPlayer.d.ts +3 -0
- package/dist/services/adPlayer/SharedElementBreakPlayer.js +1 -1
- package/dist/services/adPlayer/SuccessorQueue.d.ts +36 -0
- package/dist/services/adPlayer/SuccessorQueue.js +1 -0
- package/dist/services/adPlayer/SurfaceRevealReporter.d.ts +28 -0
- package/dist/services/adPlayer/SurfaceRevealReporter.js +1 -0
- package/dist/services/adPlayer/presentation/DomPresentationHost.d.ts +22 -0
- package/dist/services/adPlayer/presentation/DomPresentationHost.js +1 -0
- package/dist/services/adPlayer/presentation/LayoutTransform.d.ts +28 -0
- package/dist/services/adPlayer/presentation/LayoutTransform.js +1 -0
- package/dist/services/adPlayer/presentation/PresentationLayout.d.ts +19 -0
- package/dist/services/adPlayer/presentation/PresentationLayout.js +1 -0
- package/dist/services/assetParameterMacroTable.js +1 -1
- package/dist/services/assetParameterMacros.d.ts +9 -9
- package/dist/services/assetParameterMacros.js +1 -1
- package/dist/services/channelSwitch.d.ts +2 -2
- package/dist/services/externalPlaybackDiagnostic.d.ts +3 -0
- package/dist/services/externalPlaybackDiagnostic.js +1 -0
- package/dist/services/externalPlaybackGuard.d.ts +24 -0
- package/dist/services/externalPlaybackGuard.js +1 -0
- package/dist/services/parseBreakManifest.d.ts +2 -1
- package/dist/services/parseBreakManifest.js +1 -1
- package/dist/services/resolveChannelEvents.d.ts +17 -0
- package/dist/services/resolveChannelEvents.js +1 -0
- package/dist/services/resolveExternalVendorConfigurations.js +1 -1
- package/dist/services/resolveGamVendorConfiguration.d.ts +6 -1
- package/dist/services/resolveGamVendorConfiguration.js +1 -1
- package/dist/services/ssbStream.d.ts +39 -0
- package/dist/services/ssbStream.js +1 -0
- package/dist/services/ssbSwitchSignals.d.ts +15 -0
- package/dist/services/ssbSwitchSignals.js +1 -0
- package/dist/services/staticAssetUrl.d.ts +28 -0
- package/dist/services/staticAssetUrl.js +1 -0
- package/dist/session/AdBreakStatusTracker.d.ts +18 -0
- package/dist/session/AdBreakStatusTracker.js +1 -1
- package/dist/session/BreakLifecycle.d.ts +6 -0
- package/dist/session/BreakLifecycle.js +1 -1
- package/dist/session/SessionStarter.d.ts +6 -43
- package/dist/session/SessionStarter.js +1 -1
- package/dist/session/SessionStarterDeps.d.ts +39 -0
- package/dist/session/SessionStarterDeps.js +1 -0
- package/dist/session/SessionStarterHelpers.d.ts +36 -0
- package/dist/session/SessionStarterHelpers.js +1 -0
- package/dist/session/SessionState.d.ts +22 -2
- package/dist/session/SessionState.js +1 -1
- package/dist/session/SsbSwitch.d.ts +55 -0
- package/dist/session/SsbSwitch.js +1 -0
- package/dist/session/breakMeasurement.d.ts +16 -0
- package/dist/session/breakMeasurement.js +1 -0
- package/dist/session/contentSnapback.d.ts +13 -0
- package/dist/session/contentSnapback.js +1 -0
- package/dist/session/createExternalPlaybackGate.d.ts +19 -0
- package/dist/session/createExternalPlaybackGate.js +1 -0
- package/dist/session/sessionTick.d.ts +7 -0
- package/dist/session/sessionTick.js +1 -0
- package/dist/types/BreakManifest.d.ts +58 -5
- package/dist/types/Events.d.ts +21 -10
- package/dist/types/ExternalVendorConfiguration.d.ts +3 -1
- package/dist/types/OptiViewAdsConfig.d.ts +24 -8
- package/package.json +5 -1
|
@@ -12,62 +12,10 @@ import type { PauseAdResolution } from './PauseAdController';
|
|
|
12
12
|
import { type Clock } from './BreakScheduler';
|
|
13
13
|
import { PauseAdPresenter } from './adPlayer/PauseAdPresenter';
|
|
14
14
|
import { AssetParameterResolver } from './adPlayer/AssetParameterResolver';
|
|
15
|
+
import { GamPodBridge } from './adPlayer/GamPodBridge';
|
|
15
16
|
import type { BreakEndOnStreamClock } from './adPlayer/streamClockResume';
|
|
16
|
-
|
|
17
|
-
export
|
|
18
|
-
adId?: string | undefined;
|
|
19
|
-
creativeId?: string | undefined;
|
|
20
|
-
/** 1-based position within the pod (IMA `getAdPodInfo().getAdPosition()` / VAST `sequence`); absent when unreported. */
|
|
21
|
-
podPosition?: number | undefined;
|
|
22
|
-
}
|
|
23
|
-
export interface AdPlayerCallbacks {
|
|
24
|
-
onAdStart: (breakInfo: Break, asset: Asset, index: number, total: number, identity?: AdCreativeIdentity) => void;
|
|
25
|
-
onAdEnd: (breakInfo: Break, asset: Asset, index: number, total: number, identity?: AdCreativeIdentity) => void;
|
|
26
|
-
/** `asset` is undefined for a break-level error (no playable variant, the break never began). */
|
|
27
|
-
onAdError: (breakInfo: Break, asset: Asset | undefined, error: Error) => void;
|
|
28
|
-
onAdTimeUpdate: (breakInfo: Break, asset: Asset, currentTime: number, duration: number) => void;
|
|
29
|
-
onAdWaiting: (breakInfo: Break, asset: Asset) => void;
|
|
30
|
-
onAdPlaying: (breakInfo: Break, asset: Asset) => void;
|
|
31
|
-
onBreakEnd: (breakInfo: Break) => void;
|
|
32
|
-
/** The break-cut timer expired with an ad still in flight; fired before that ad's `adend`. */
|
|
33
|
-
onBreakCut?: (breakInfo: Break) => void;
|
|
34
|
-
/**
|
|
35
|
-
* A content-covering break ended before its content pause landed, so no player transition
|
|
36
|
-
* announces the resume. Only the deferred-pause renderers (Kotlin/Swift) fire this.
|
|
37
|
-
*/
|
|
38
|
-
onBreakEndedWithoutContentPause?: (breakInfo: Break) => void;
|
|
39
|
-
/** Ad overlay became visible; gates `adbreakbegin` so the AD badge never precedes the first ad frame. */
|
|
40
|
-
onBreakVisible?: (breakInfo: Break) => void;
|
|
41
|
-
/** The current break soft-ended into a chained successor (overlay held, no content resume). */
|
|
42
|
-
onChainedBreakBegin?: (next: Break) => void;
|
|
43
|
-
/** A chained successor resolved but has nothing to play; the SDK must retire it (completeBreak). */
|
|
44
|
-
onChainedBreakSkipped?: (next: Break) => void;
|
|
45
|
-
/**
|
|
46
|
-
* Fired just before the runtime's own post-break resume-seek, so the scheduler does not read
|
|
47
|
-
* the backward step as a DVR seek-back and re-arm the break.
|
|
48
|
-
*/
|
|
49
|
-
onContentResumeSeek?: (targetSeconds: number, breakEndSeconds: number) => void;
|
|
50
|
-
/**
|
|
51
|
-
* Brackets a content RELOAD (shared-element break end), so the playhead passing through the
|
|
52
|
-
* start of the freshly loaded stream is not read as a seek back before the break.
|
|
53
|
-
*/
|
|
54
|
-
onContentReloading?: (active: boolean) => void;
|
|
55
|
-
}
|
|
56
|
-
export interface PlayBreakOptions {
|
|
57
|
-
/** Seconds to present the break for (tune-in breaks: the remaining time); defaults to `break.duration`. */
|
|
58
|
-
effectiveDurationSec?: number;
|
|
59
|
-
/** Defer the overlay and `onBreakVisible` until the first ad frame renders (held delay:0 fullscreen pre-rolls). */
|
|
60
|
-
firstFrameGate?: boolean;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* IMA quartile callbacks. `adIndex`/`totalAds` attribute the milestone to one ad of a
|
|
64
|
-
* multi-ad GAM pod; omitted when there is no per-ad breakdown.
|
|
65
|
-
*/
|
|
66
|
-
export interface GamEventCallbacks {
|
|
67
|
-
onAdFirstQuartile?: (breakInfo: Break, asset: Asset, adIndex?: number, totalAds?: number) => void;
|
|
68
|
-
onAdMidpoint?: (breakInfo: Break, asset: Asset, adIndex?: number, totalAds?: number) => void;
|
|
69
|
-
onAdThirdQuartile?: (breakInfo: Break, asset: Asset, adIndex?: number, totalAds?: number) => void;
|
|
70
|
-
}
|
|
17
|
+
import type { AdCreativeIdentity, AdPlayerCallbacks, GamEventCallbacks, PlayBreakOptions } from './adPlayer/AdPlayerCallbacks';
|
|
18
|
+
export type { AdCreativeIdentity, AdPlayerCallbacks, GamEventCallbacks, PlayBreakOptions };
|
|
71
19
|
export declare class AdPlayerController {
|
|
72
20
|
private static readonly AD_START_BUDGET_MS;
|
|
73
21
|
private static readonly GAM_POD_AD_START_BUDGET_MS;
|
|
@@ -79,6 +27,7 @@ export declare class AdPlayerController {
|
|
|
79
27
|
private createAdAdapter;
|
|
80
28
|
private adMediaContainer;
|
|
81
29
|
private adPlayer;
|
|
30
|
+
private readonly surfaceReveal;
|
|
82
31
|
private adContainer;
|
|
83
32
|
private companionElement;
|
|
84
33
|
private staticQuartilesFired;
|
|
@@ -99,12 +48,13 @@ export declare class AdPlayerController {
|
|
|
99
48
|
private readonly state;
|
|
100
49
|
readonly pauseAdPresenter: PauseAdPresenter;
|
|
101
50
|
private readonly assetParameters;
|
|
102
|
-
|
|
51
|
+
readonly gamPodBridge: GamPodBridge;
|
|
103
52
|
private readonly adStage;
|
|
104
53
|
private destroyed;
|
|
105
54
|
private readonly preloader;
|
|
106
55
|
private readonly assetPlayback;
|
|
107
56
|
private readonly breakSequenceDriver;
|
|
57
|
+
private readonly successorQueue;
|
|
108
58
|
private readonly variantSelector;
|
|
109
59
|
private readonly adPlayerEvents;
|
|
110
60
|
private get gamEventCallbacks();
|
|
@@ -139,9 +89,7 @@ export declare class AdPlayerController {
|
|
|
139
89
|
private readonly presentationModes;
|
|
140
90
|
private readonly sharedElementPlayer;
|
|
141
91
|
private readonly resumeCoordinator;
|
|
142
|
-
private
|
|
143
|
-
private contentVolumeHandler;
|
|
144
|
-
private adVolumeChangeHandler;
|
|
92
|
+
private readonly audio;
|
|
145
93
|
private volumeChangeCallback;
|
|
146
94
|
private stage;
|
|
147
95
|
private resizeObserver;
|
|
@@ -213,7 +161,6 @@ export declare class AdPlayerController {
|
|
|
213
161
|
* not undo it: re-boxing a rolling creative would re-fetch a skipped companion and un-pause content.
|
|
214
162
|
*/
|
|
215
163
|
private doubleBoxAudio;
|
|
216
|
-
private audioFocus;
|
|
217
164
|
constructor(contentPlayer: PlayerAdapter, container: HTMLElement, playerContainer: HTMLElement | undefined, createAdAdapter: CreateAdAdapter, debug?: boolean, gamConfig?: GamConfig, preloadMode?: ResolvedPreloadMode, insertionMode?: ResolvedInsertionMode, adBreakCutSafetyMarginSec?: number, doubleBoxAudio?: DoubleBoxAudio, singleSurfaceDevice?: boolean,
|
|
218
165
|
/** Injected so drift correction is deterministic under fake timers; reuses the scheduler's `Clock`. */
|
|
219
166
|
clock?: Clock, contentRecovery?: ResolvedContentRecovery);
|
|
@@ -235,6 +182,8 @@ export declare class AdPlayerController {
|
|
|
235
182
|
private clearContentGate;
|
|
236
183
|
/** `null` disables chaining: breaks then always hard-end regardless of how close the next one is. */
|
|
237
184
|
setChainResolver(resolver: ((currentBreakId: string) => Break | null) | null): void;
|
|
185
|
+
/** The playing break's chained successor appeared, changed or disappeared: re-queue or drop its first ad. */
|
|
186
|
+
onChainSuccessorChanged(): void;
|
|
238
187
|
/** {@link ContentResumeCoordinator.setCueAnchorResolver}. */
|
|
239
188
|
setResumeCueAnchorResolver(resolver: ((breakInfo: Break) => number | null) | null): void;
|
|
240
189
|
/** {@link ContentResumeCoordinator.setCueEndResolver}. */
|
|
@@ -279,6 +228,7 @@ export declare class AdPlayerController {
|
|
|
279
228
|
setSessionAssetParameterMacros(macros: AssetParameterMacros | undefined): void;
|
|
280
229
|
get sessionAssetParameterMacros(): AssetParameterMacros;
|
|
281
230
|
private buildVastTagUrl;
|
|
231
|
+
private buildStaticAssetUrl;
|
|
282
232
|
private pushAssetParameters;
|
|
283
233
|
private setupOverlay;
|
|
284
234
|
/** Always creates a fresh IMA session. */
|
|
@@ -413,11 +363,6 @@ export declare class AdPlayerController {
|
|
|
413
363
|
declaredFormatOf(breakInfo: Break): BreakFormat | undefined;
|
|
414
364
|
private getVariant;
|
|
415
365
|
private applyLayout;
|
|
416
|
-
/**
|
|
417
|
-
* For double/lshape_ad/lshape_content, playerContainer keeps its break-time z-index (101)
|
|
418
|
-
* during the transition so it stays above the still-fading adContainer (z:100) and companion
|
|
419
|
-
* (z:99); otherwise the backdrop cuts to black instead of content growing back.
|
|
420
|
-
*/
|
|
421
366
|
private restoreLayout;
|
|
422
367
|
/**
|
|
423
368
|
* Selection-aware: without the inputs, a device-targeted variant's assets would read as empty
|
|
@@ -488,20 +433,14 @@ export declare class AdPlayerController {
|
|
|
488
433
|
private show;
|
|
489
434
|
private hide;
|
|
490
435
|
isAdPlaying(): boolean;
|
|
491
|
-
/**
|
|
492
|
-
* Reads/writes the effective audio owner — the ad player during a break, content otherwise.
|
|
493
|
-
* The `volumechange` sync mirrors onto the other side; a CSAI ad is bridged via
|
|
494
|
-
* {@link VastAdManager.setMuted} (IMA manages its own audio path). With an active
|
|
495
|
-
* {@link audioFocus} only the focused side is targeted.
|
|
496
|
-
*/
|
|
436
|
+
/** The viewer's audio state, applied to both players; see {@link AudioController}. */
|
|
497
437
|
get muted(): boolean;
|
|
498
438
|
set muted(value: boolean);
|
|
499
|
-
/** 0-1. See {@link muted}
|
|
439
|
+
/** 0-1. See {@link muted}. */
|
|
500
440
|
get volume(): number;
|
|
501
441
|
set volume(value: number);
|
|
502
442
|
/** Invoked with the current {@link muted}/{@link volume} whenever either changes. Pass `null` to detach. */
|
|
503
443
|
setVolumeChangeCallback(callback: ((muted: boolean, volume: number) => void) | null): void;
|
|
504
|
-
private notifyVolumeChange;
|
|
505
444
|
destroy(): void;
|
|
506
445
|
private log;
|
|
507
446
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BreakFormat as e,Timebase as t,isPostRollBreak as r}from"../types/BreakManifest";import{DEFAULT_AD_BREAK_CUT_SAFETY_MARGIN_SEC as s,DEFAULT_DOUBLE_BOX_AUDIO as a}from"../types/OptiViewAdsConfig";import{pipOverridesFormat as i,pipSuppressesBackdrop as n}from"./pictureInPicture";import{AdBreakSequencer as o,assetsOfVariant as d,resolveBreakFormat as l}from"./AdBreakSequencer";import{selectVariantDetailed as h}from"./selectVariant";import{debugLog as u}from"../diagnostics/debugLog";import{systemClock as c}from"./BreakScheduler";import{createAdPlayerState as m,invalidateMediaPreload as g}from"./adPlayer/AdPlayerState";import{PauseAdPresenter as P}from"./adPlayer/PauseAdPresenter";import{AssetParameterResolver as y}from"./adPlayer/AssetParameterResolver";import{GamPodBridge as p}from"./adPlayer/GamPodBridge";import{AdStage as A}from"./adPlayer/AdStage";import{AdPreloader as v}from"./adPlayer/AdPreloader";import{PresentationModeTracker as C}from"./adPlayer/PresentationModeTracker";import{SharedElementBreakPlayer as k}from"./adPlayer/SharedElementBreakPlayer";import{ContentResumeCoordinator as f}from"./adPlayer/ContentResumeCoordinator";import{resumeContentAfterBreak as S}from"./adPlayer/ContentRecovery";import{AssetPlayback as B}from"./adPlayer/AssetPlayback";import{BreakSequenceDriver as E}from"./adPlayer/BreakSequenceDriver";import{VariantSelector as b}from"./adPlayer/VariantSelector";import{AdPlayerEvents as F}from"./adPlayer/AdPlayerEvents";import{armPlaybackCutoff as T,clearPlaybackCutoff as M}from"./adPlayer/PlaybackCutoff";import{AdError as R}from"../types/AdError";export class AdPlayerController{get contentPaused(){return this.state.contentPaused}set contentPaused(e){this.state.contentPaused=e}get firstFrameGateActive(){return this.state.firstFrameGateActive}set firstFrameGateActive(e){this.state.firstFrameGateActive=e}get firstFrameGateShown(){return this.state.firstFrameGateShown}set firstFrameGateShown(e){this.state.firstFrameGateShown=e}get firstFrameRejector(){return this.state.firstFrameRejector}set firstFrameRejector(e){this.state.firstFrameRejector=e}get gamEventCallbacks(){return this.gamPodBridge.eventCallbacks}get vastAdManager(){return this.state.vastAdManager}set vastAdManager(e){this.state.vastAdManager=e}get currentBreak(){return this.state.currentBreak}set currentBreak(e){this.state.currentBreak=e}get currentAsset(){return this.state.currentAsset}set currentAsset(e){this.state.currentAsset=e}get callbacks(){return this.state.callbacks}set callbacks(e){this.state.callbacks=e}get isPlaying(){return this.state.isPlaying}set isPlaying(e){this.state.isPlaying=e}get effectiveBreakDurationSec(){return this.state.effectiveBreakDurationSec}set effectiveBreakDurationSec(e){this.state.effectiveBreakDurationSec=e}get adBreakCutSafetyMarginSec(){return this.state.adBreakCutSafetyMarginSec}set adBreakCutSafetyMarginSec(e){this.state.adBreakCutSafetyMarginSec=e}get durationTimer(){return this.state.durationTimer}set durationTimer(e){this.state.durationTimer=e}get adInsertionType(){return this.state.adInsertionType}set adInsertionType(e){this.state.adInsertionType=e}get breakTimebase(){return this.state.breakTimebase}set breakTimebase(e){this.state.breakTimebase=e}constructor(e,t,r,i,n=!1,o,d="parallel",l="overlay",h=s,u=a,S=!1,T=c,M="none"){this.playerContainerCreatedBySDK=!1,this.adMediaContainer=null,this.adPlayer=null,this.adContainer=null,this.companionElement=null,this.staticQuartilesFired=new Set,this.sequencer=null,this.pendingAdError=null,this.preRollHoldActive=!1,this.preRollHoldHandler=null,this.breakContentGateHandler=null,this.destroyed=!1,this.abortingBreak=!1,this.overlayImageEl=null,this.imageAssetTimer=null,this.chainResolver=null,this.transitionPhaseReporter=null,this.chaining=!1,this.diagnoseHandler=null,this.playerContainerOriginalStyle="",this.companionRemoveTimer=null,this.adFadeTimer=null,this.syncing=!1,this.contentVolumeHandler=null,this.adVolumeChangeHandler=null,this.volumeChangeCallback=null,this.stage=null,this.resizeObserver=null,this.contentVideoElement=null,this.contentVideoGeometryHandler=null,this.contentVideoMutationObserver=null,this.resumeGeneration=0,this.singleSurfaceDevice=!1,this.currentSelectedFormat=void 0,this.audioFocus=null,this.state=m(),this.state.playerContainer=r??null,this.clock=T,this.singleSurfaceDevice=S,this.contentPlayer=e,this.adBreakCutSafetyMarginSec=h,this.doubleBoxAudio=u,this.container=t,r&&(this.playerContainer=r),this.createAdAdapter=i,this.debug=n,this.state.gamConfig=o,this.preloadMode=d,this.insertionMode=l,this.pauseAdPresenter=new P({contentPlayer:this.contentPlayer,getStage:()=>this.stage,resolveUri:e=>this.resolveUri(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.assetParameters=new y(this.state,{contentPlayer:this.contentPlayer,container:this.container,getGamStreamManager:()=>this.state.gamStreamManager,getCurrentBreak:()=>this.currentBreak,getEffectiveBreakDuration:()=>this.effectiveBreakDurationSec,diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.gamPodBridge=new p(this.state,{contentPlayer:this.contentPlayer,debug:this.debug,getAdPlayer:()=>this.adPlayer,getAdContainer:()=>this.adContainer,isSharedElement:()=>"shared-element"===this.effectiveInsertionMode(),getCurrentBreak:()=>this.currentBreak,getCurrentAsset:()=>this.currentAsset,getEffectiveBreakDuration:()=>this.effectiveBreakDurationSec,getAdPlayerStreamRemainingSec:()=>this.adPlayerStreamRemainingSec(),emitStep:e=>this.emitStep(e),emitAdStart:(e,t,r,s,a)=>this.callbacks?.onAdStart(e,t,r,s,a),emitAdEnd:(e,t,r,s,a)=>this.callbacks?.onAdEnd(e,t,r,s,a),onAdEnded:()=>this.onAdEnded(),pushAssetParameters:(e,t)=>this.pushAssetParameters(e,t),resolveSessionAdTagParameters:()=>this.assetParameters.resolveSessionAdTagParameters(),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.adStage=new A({contentPlayer:this.contentPlayer,container:this.container,getPlayerContainer:()=>this.playerContainer,setPlayerContainer:e=>{this.playerContainer=e},setPlayerContainerOriginalStyle:e=>{this.playerContainerOriginalStyle=e},onPlayerContainerCreated:()=>{this.playerContainerCreatedBySDK=!0},getStage:()=>this.stage,setStage:e=>{this.stage=e},getContentVideo:()=>this.contentVideoElement,setContentVideo:e=>{this.contentVideoElement=e},getAdContainer:()=>this.adContainer,setAdContainer:e=>{this.adContainer=e},getAdMediaContainer:()=>this.adMediaContainer,setAdMediaContainer:e=>{this.adMediaContainer=e},setAdPlayer:e=>{g(this.state),this.adPlayer=e},createAdAdapter:e=>this.createAdAdapter(e),setupEventListeners:()=>this.setupEventListeners(),resizeVast:()=>this.vastAdManager?.resize(),getVariant:e=>this.getVariant(e),getCurrentBreak:()=>this.currentBreak,resolveUri:e=>this.resolveUri(e),getCompanion:()=>this.companionElement,setCompanion:e=>{this.companionElement=e},getOverlayImage:()=>this.overlayImageEl,setOverlayImage:e=>{this.overlayImageEl=e},getImageAssetTimer:()=>this.imageAssetTimer,setImageAssetTimer:e=>{this.imageAssetTimer=e},isChaining:()=>this.chaining,log:(...e)=>this.log(...e)}),this.preloader=new v({state:this.state,clock:this.clock,adStartBudgetMs:AdPlayerController.AD_START_BUDGET_MS,gamPodAdStartBudgetMs:AdPlayerController.GAM_POD_AD_START_BUDGET_MS,minAdStartBudgetMs:AdPlayerController.MIN_AD_START_BUDGET_MS,debug:this.debug,isPlaying:()=>this.isPlaying,preloadMode:this.preloadMode,effectiveInsertionMode:()=>this.effectiveInsertionMode(),getVariant:e=>this.getVariant(e),getAssets:e=>this.getAssets(e),resolveUri:e=>this.resolveUri(e),resolveAssetUri:(e,t)=>this.resolveAssetUri(e,t),getCompanionVariant:e=>this.getVariant(e),getAdPlayer:()=>this.adPlayer,getAdContainer:()=>this.adContainer,buildVastTagUrl:(e,t)=>this.buildVastTagUrl(e,t),resolveChainedSuccessor:e=>this.resolveChainedSuccessor(e),show:()=>this.show(),reapplyAdContainerLayout:e=>this.reapplyAdContainerLayout(e),getCurrentBreak:()=>this.currentBreak,onBreakVisible:e=>this.callbacks?.onBreakVisible?.(e),onAdError:e=>this.onAdError(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.presentationModes=new C(this.state,{contentPlayer:this.contentPlayer,getAdPlayer:()=>this.adPlayer,insertionMode:this.insertionMode,getCurrentBreak:()=>this.currentBreak,getCurrentFormat:()=>this.currentSelectedFormat,isSharedElementActive:()=>this.state.sharedAdClaimActive,getVariant:e=>this.getVariant(e),isAdPlaying:()=>this.isAdPlaying(),hasCurrentAsset:()=>null!==this.currentAsset,contentSourceIsReloadable:()=>null!==this.sharedElementPlayer.restorableContentSource(),adoptPictureInPictureMidBreak:()=>this.adoptPictureInPictureMidBreak(),restoreLayout:e=>this.restoreLayout(e),applyLayout:e=>this.applyLayout(e),show:()=>this.show(),playAdThroughContentElement:()=>this.sharedElementPlayer.playAdThroughContentElement(),getContentPositionAtBreakStart:()=>this.state.contentPositionAtBreakStart,setContentPositionAtBreakStart:e=>this.resumeCoordinator.reanchorMidBreak(e),gateContentForBreak:()=>this.gateContentForBreak(),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.resumeCoordinator=new f(this.state,{contentPlayer:this.contentPlayer,clock:this.clock,getInsertionMode:()=>this.effectiveInsertionMode(),gateContentForBreak:()=>this.gateContentForBreak(),clearContentGate:e=>this.clearContentGate(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.recoveryDeps={contentPlayer:e,getCallbacks:()=>this.callbacks,preloadMode:d,contentRecovery:M,resumeCoordinator:this.resumeCoordinator,diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)},this.sharedElementPlayer=new k(this.state,{contentPlayer:this.contentPlayer,getAdPlayer:()=>this.adPlayer,resolveAssetUri:(e,t)=>this.resolveAssetUri(e,t),liveEdgeDistanceSec:()=>this.resumeCoordinator.liveEdgeDistanceSec(),rebindContentElementIfSwapped:()=>this.rebindContentElementIfSwapped(),createAdAdapter:(e,t)=>this.createAdAdapter(e,t),reportAdProgress:e=>this.reportAdProgress(e),processTimedMetadata:e=>this.gamPodBridge.processTimedMetadata(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e),clearContentGate:()=>this.clearContentGate(),hide:()=>this.hide(),waitForLiveEdge:e=>this.resumeCoordinator.waitForLiveEdge(e),getVariant:e=>this.getVariant(e),getAssets:e=>this.getAssets(e)}),this.variantSelector=new b(this.state,{getEffectiveInsertionMode:()=>this.effectiveInsertionMode(),singleSurfaceDevice:this.singleSurfaceDevice,preloadMode:this.preloadMode,getIsContentPictureInPicture:()=>this.isContentPictureInPicture(),getIsGamReady:()=>this.isGamReady(),getSupportsParallelBuffering:()=>this.contentPlayer.supportsParallelBuffering,diagnose:(e,t,r)=>this.diagnose(e,t,r)}),this.assetPlayback=new B(this.state,{getAdPlayer:()=>this.adPlayer,getAdContainer:()=>this.adContainer,getAdMediaContainer:()=>this.adMediaContainer,clearStaticQuartiles:()=>this.staticQuartilesFired.clear(),getVariant:e=>this.getVariant(e),getGamEventCallbacks:()=>this.gamEventCallbacks,getSequencer:()=>this.sequencer,debug:this.debug,resolveUri:e=>this.resolveUri(e),buildGamUrl:(e,t)=>this.buildGamUrl(e,t),buildVastTagUrl:(e,t)=>this.buildVastTagUrl(e,t),onAdError:e=>this.onAdError(e),onAdEnded:()=>this.onAdEnded(),drive:e=>this.drive(e),clearOverlayImage:()=>this.clearOverlayImage(),revealFirstFrame:()=>this.preloader.revealFirstFrame(),transferPictureInPictureToAd:()=>this.presentationModes.transferPictureInPictureToAd(),isGamPodAsset:e=>this.isGamPodAsset(e),hasGamIdentityMismatch:e=>this.gamPodBridge.hasIdentityMismatch(e),beginGamPodTracking:e=>this.gamPodBridge.beginGamPodTracking(e),recordAdProgress:e=>this.adPlayerEvents.recordAdProgress(e),reportPhase:e=>this.reportPhase(e),armAdStartBudget:e=>this.armAdStartBudget(e),remainingAdStartBudgetMs:()=>this.remainingAdStartBudgetMs(),loadWithinBudget:(e,t)=>this.loadWithinBudget(e,t),waitForFirstFrame:()=>this.waitForFirstFrame(),getOverlayImage:()=>this.overlayImageEl,setOverlayImage:e=>{this.overlayImageEl=e},getImageAssetTimer:()=>this.imageAssetTimer,setImageAssetTimer:e=>{this.imageAssetTimer=e},getVastPodPosition:()=>this.vastPodPosition,setVastPodPosition:e=>{this.vastPodPosition=e},diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.breakSequenceDriver=new E(this.state,{getChainResolver:()=>this.chainResolver,getEffectiveInsertionMode:()=>this.effectiveInsertionMode(),getVastPodPosition:()=>this.vastPodPosition,setVastPodPosition:e=>{this.vastPodPosition=e},getPendingAdError:()=>this.pendingAdError,setPendingAdError:e=>{this.pendingAdError=e},getChaining:()=>this.chaining,setChaining:e=>{this.chaining=e},isExpandingPodAsset:e=>this.isExpandingPodAsset(e),fallBackToPodLevelReporting:()=>this.fallBackToPodLevelReporting(),resetGamPodTracking:()=>this.resetGamPodTracking(),emitGamPodSteps:e=>this.gamPodBridge.emitGamPodSteps(e),playAsset:(e,t,r)=>this.playAsset(e,t,r),endBreak:()=>this.endBreak(),playBreak:(e,t,r)=>this.playBreak(e,t,r),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.adPlayerEvents=new F(this.state,{getAdPlayer:()=>this.adPlayer,getContentPlayer:()=>this.contentPlayer,getGamEventCallbacks:()=>this.gamEventCallbacks,getSequencer:()=>this.sequencer,getAudioFocus:()=>this.audioFocus,getSyncing:()=>this.syncing,setSyncing:e=>{this.syncing=e},setAdVolumeChangeHandler:e=>{this.adVolumeChangeHandler=e},setContentVolumeHandler:e=>{this.contentVolumeHandler=e},notifyVolumeChange:()=>this.notifyVolumeChange(),onAdEnded:()=>this.onAdEnded(),processTimedMetadata:e=>this.gamPodBridge.processTimedMetadata(e),toAdError:e=>this.toAdError(e),revealFirstFrame:()=>this.revealFirstFrame(),clearFirstFrameResolver:()=>this.preloader.clearFirstFrameResolver(),drive:e=>this.drive(e),setPendingAdError:e=>{this.pendingAdError=e},log:(...e)=>this.log(...e),maybePrepositionContentForResume:()=>"single-decoder"!==this.preloadMode&&this.resumeCoordinator.maybePrepositionContentForResume(),maybeCatchUpContentForResume:e=>"single-decoder"!==this.preloadMode&&this.resumeCoordinator.maybeCatchUpContentForResume(e),getStaticQuartilesFired:()=>this.staticQuartilesFired,onGamPodAdProgress:e=>this.gamPodBridge.onGamPodAdProgress(e)})}setGamEventCallbacks(e){this.gamPodBridge.setEventCallbacks(e)}setDiagnoseHandler(e){this.diagnoseHandler=e}diagnose(e,t,r){this.diagnoseHandler?.(e,t,r)}holdContentForPreRoll(e){if(this.preRollHoldActive)return;const t=this.getVariant(e);t&&this.shouldPauseContent(t.format)&&(this.preRollHoldActive=!0,this.contentPlayer.pause(),this.preRollHoldHandler=()=>{this.preRollHoldActive&&this.contentPlayer.pause()},this.contentPlayer.on("playing",this.preRollHoldHandler),this.diagnose("DA-PREROLL-CONTENT-HELD","Content held at session start until the pending pre-roll begins.",{breakId:e.id}))}releaseContentHold(){this.preRollHoldActive&&(this.preRollHoldActive=!1,this.preRollHoldHandler&&(this.contentPlayer.off("playing",this.preRollHoldHandler),this.preRollHoldHandler=null))}gateContentForBreak(){this.contentPlayer.pause(),this.breakContentGateHandler||(this.breakContentGateHandler=()=>{this.contentPaused&&!this.state.resumeCatchupActive&&this.contentPlayer.pause()},this.contentPlayer.on("playing",this.breakContentGateHandler))}clearContentGate(e=!1){this.resumeCoordinator.endResumeCatchup(e),this.breakContentGateHandler&&(this.contentPlayer.off("playing",this.breakContentGateHandler),this.breakContentGateHandler=null)}setChainResolver(e){this.chainResolver=e}setResumeCueAnchorResolver(e){this.resumeCoordinator.setCueAnchorResolver(e)}setResumeCueEndResolver(e){this.resumeCoordinator.setCueEndResolver(e)}ingestStreamClockCue(e){this.resumeCoordinator.ingestStreamClockCue(e)}setTransitionPhaseReporter(e){this.transitionPhaseReporter=e}reportPhase(e){this.transitionPhaseReporter?.(e)}setBreakResumePolicy(e,t,r=!1){this.adInsertionType=e,this.breakTimebase=t,this.state.continueContentDuringBreak=r,this.state.continueRefusalReported=!1}initialize(){this.adContainer||(this.setupOverlay(),this.presentationModes.setupPictureInPictureTracking(),"adaptive"===this.insertionMode&&this.presentationModes.setupFullscreenTracking())}async startGamSession(e,t){await this.gamPodBridge.startGamSession(e,t)}endGamSession(){this.gamPodBridge.endGamSession()}setSessionAssetParameters(e){this.assetParameters.setSessionAssetParameters(e)}setManifestAssetParameters(e){this.assetParameters.setManifestAssetParameters(e)}updateAssetParameters(e){this.assetParameters.updateAssetParameters(e)}resolveExternalVendorConfiguration(e){return this.assetParameters.resolveExternalVendorConfiguration(e)}updateAssetParameterMacros(e){this.assetParameters.updateAssetParameterMacros(e)}get updatedAssetParameters(){return this.state.updatedAssetParameters}setSessionAssetParameterMacros(e){this.assetParameters.setSessionAssetParameterMacros(e)}get sessionAssetParameterMacros(){return this.assetParameters.getSessionAssetParameterMacros()}buildVastTagUrl(e,t){return this.assetParameters.buildVastTagUrl(e,t)}pushAssetParameters(e,t){this.assetParameters.pushAssetParameters(e,t)}setupOverlay(){this.adStage.setupOverlay()}isGamPodAsset(e){return this.gamPodBridge.isGamPodAsset(e)}isExpandingPodAsset(e){return this.gamPodBridge.isExpandingPodAsset(e)}fallBackToPodLevelReporting(){this.gamPodBridge.fallBackToPodLevelReporting()}resetGamPodTracking(){this.gamPodBridge.resetGamPodTracking()}emitGamPodSteps(e){this.gamPodBridge.emitGamPodSteps(e)}isGamEnabled(){return this.gamPodBridge.isGamEnabled()}isGamReady(){return this.gamPodBridge.isGamReady()}isOverlayInsertion(){return"overlay"===this.effectiveInsertionMode()}settleAssetProgress(){this.adPlayerEvents.settleAssetProgress()}reportAdProgress(e){this.adPlayerEvents.reportAdProgress(e)}setupEventListeners(){this.adPlayerEvents.setupEventListeners()}async preload(e){return this.preloader.preload(e)}renderLshapeContentBackdrop(e){this.adStage.renderLshapeContentBackdrop(e)}currentInsertionMode(){return this.presentationModes.currentInsertionMode()}effectiveInsertionMode(){return this.presentationModes.effectiveInsertionMode()}isContentPictureInPicture(){return this.presentationModes.isPictureInPicture()}rebindContentElementIfSwapped(){this.presentationModes.rebindContentElementIfSwapped()}teardownFullscreenTracking(){this.presentationModes.teardownFullscreenTracking()}teardownPictureInPictureTracking(){this.presentationModes.teardownPictureInPictureTracking()}isPictureInPicture(){return this.presentationModes.isPictureInPicture()}pictureInPictureOwner(){return this.presentationModes.pictureInPictureOwner()}isShowingAd(){if(!this.isAdPlaying())return!1;const e=this.currentDeclaredFormat();return!n(e,this.isContentPictureInPicture())}currentDeclaredFormat(){return this.currentSelectedFormat??(this.currentBreak?l(this.currentBreak):void 0)}async playBreak(t,s,a){if(this.state.preloadGeneration++,this.resumeGeneration++,!this.sharedElementPlayer.beginSharedActivity())return;this.releaseContentHold(),this.rebindContentElementIfSwapped();const n=a?.effectiveDurationSec??null;this.effectiveBreakDurationSec=null!==n&&n>0?n:null;const d=this.effectiveBreakDurationSec??t.duration;if("shared-element"===this.effectiveInsertionMode())return g(this.state),void await this.sharedElementPlayer.playSharedElementBreak(t,s);if(!this.adPlayer)return void this.log("playBreak called before initialize()");const l=this.getVariant(t);if(!l)return void this.log("No valid variant found for break:",t.id);this.currentBreak=t,this.callbacks=s,this.isPlaying=!0,this.firstFrameGateActive=a?.firstFrameGate??!1,this.firstFrameGateShown=!1;const h=this.continueContentDuringBreakReason(l.format),u=r(t),c=this.shouldPauseContent(l.format)&&"ok"===h&&!u;c||u||this.state.continueRefusalReported||!this.shouldPauseContent(l.format)||(this.state.continueRefusalReported=!0,this.diagnose("DA-CONTINUE-PLAYOUT-REFUSED",`Content will be paused for breaks this session: ${h}`,{reason:h,format:l.format})),this.audioFocus=l.format===e.DOUBLE?this.doubleBoxAudio:c?"ad":null,this.adPlayer&&("content"===this.audioFocus?(this.adPlayer.muted=!0,this.adPlayer.volume=0):(this.adPlayer.muted=this.contentPlayer.muted,this.adPlayer.volume=this.contentPlayer.volume,"ad"===this.audioFocus&&(this.contentPlayer.muted=!0)));const m=this.declaredFormatOf(t);if(this.currentSelectedFormat=m,this.state.pipAdoptedForBreak=i(m,this.isContentPictureInPicture()),this.state.pipAdoptedForBreak&&this.diagnose("DA-PIP-FORMAT-OVERRIDE",`Picture-in-picture: ${m} break plays as single`,{declared:m,effective:e.SINGLE,reason:"picture-in-picture",midBreak:!1}),this.shouldPauseContent(l.format)?(this.resumeCoordinator.captureBreakAnchor(t),c?(this.contentPaused=!1,this.resumeCoordinator.beginContinueContentPlayout()):(this.contentPaused=!0,this.gateContentForBreak())):this.contentPaused=!1,this.applyLayout(l),l.format===e.LSHAPE_CONTENT)return this.renderLshapeContentBackdrop(l),void(d&&d>0?(this.log("Starting duration timer:",d,"seconds"),this.durationTimer=setTimeout(()=>{this.log("Duration timer expired, ending break"),this.endBreak()},1e3*d)):this.endBreak());this.firstFrameGateActive||(this.show(),this.reapplyAdContainerLayout(l));if(0===this.getAssets(t).length)return this.log("No assets in break, ending immediately"),void this.endBreak();{const e=Math.max(0,d||0)+this.adBreakCutSafetyMarginSec;T(this.state,e,()=>{this.log("Break-cut timer expired, ending break"),this.firstFrameRejector?this.onAdError(new R("Break cut before first frame rendered","DA-AD-START-TIMEOUT")):this.sequencer&&this.currentBreak&&this.isPlaying?(this.callbacks?.onBreakCut?.(this.currentBreak),this.drive(this.sequencer.onOutcome({kind:"break-elapsed"}))):this.endBreak()},()=>this.onAdError(new R("Ad playback startup timed out","DA-AD-START-TIMEOUT")))}this.sequencer=new o("overlay",()=>null,this.selectionInputs()),await this.drive(this.sequencer.beginBreak(t)),this.preloadChainedSuccessor(t.id)}get resumeHandoverInMotion(){return this.state.resumeCatchupActive}reapplyAdContainerLayout(e){this.adStage.reapplyAdContainerLayout(e)}adoptPictureInPictureMidBreak(){this.presentationModes.adoptPictureInPictureMidBreak()}async restorePictureInPictureToContent(){await this.presentationModes.restorePictureInPictureToContent()}continueContentDuringBreakReason(e){return this.variantSelector.continueContentDuringBreakReason(e)}shouldPauseContent(t){return t===e.SINGLE||t===e.LSHAPE_AD}selectionInputs(){return this.variantSelector.selectionInputs()}breakNothingToPlayReason(e){return this.variantSelector.breakNothingToPlayReason(e)}unknownVariantFormatsOf(e){return this.variantSelector.unknownVariantFormatsOf(e)}diagnoseUnknownVariantFormats(e){this.variantSelector.diagnoseUnknownVariantFormats(e)}declaredFormatOf(e){const{selected:t,deviceQualified:r}=h(e,this.selectionInputs());return(t??r)?.format??l(e)}getVariant(e){return this.variantSelector.getVariant(e)}applyLayout(e){this.adStage.applyLayout(e)}restoreLayout(e){this.adStage.restoreLayout(e)}getAssets(e){return d(this.getVariant(e))}async playAsset(e,t,r){return this.assetPlayback.playAsset(e,t,r)}clearOverlayImage(){this.adStage.clearOverlayImage()}async showPauseImage(e){return this.pauseAdPresenter.showPauseImage(e)}hidePauseImage(){this.pauseAdPresenter.hidePauseImage()}async drive(e){return this.breakSequenceDriver.drive(e)}emitStep(e){this.breakSequenceDriver.emitStep(e)}async resolveAssetUri(e,t){return this.assetPlayback.resolveAssetUri(e,t)}async buildGamUrl(e,t){return this.gamPodBridge.buildGamUrl(e,t)}resolveUri(e){return this.assetParameters.resolveUri(e)}adPlayerStreamRemainingSec(){return this.assetPlayback.adPlayerStreamRemainingSec()}onAdEnded(){this.currentBreak&&this.isPlaying&&this.sequencer&&(this.settleAssetProgress(),this.drive(this.sequencer.onOutcome({kind:"asset-ended"})))}toAdError(e){return this.assetPlayback.toAdError(e)}onAdError(e){this.adPlayerEvents.onAdError(e)}endBreak(){if(!this.currentBreak)return;this.log("Break ended:",this.currentBreak.id),M(this.state),this.state.gamPodTracker&&this.emitGamPodSteps(this.state.gamPodTracker.finish()),this.resetGamPodTracking(),this.pushAssetParameters(void 0);const e=this.currentBreak,s=this.getVariant(e)?.format;let a=this.abortingBreak?null:this.resolveChainedSuccessor(e.id);if(a){const e=this.breakNothingToPlayReason(a);this.diagnoseUnknownVariantFormats(a),e&&(this.diagnose("DA-BREAK-NO-PLAYABLE-ASSET",`chained break ${a.id} has no playable variant (${e}); it will not begin.`,{breakId:a.id,reason:e}),this.callbacks?.onAdError(a,void 0,new R(`Break ${a.id} has no playable variant (${e})`,"DA-BREAK-NO-PLAYABLE-ASSET")),this.callbacks?.onChainedBreakSkipped?.(a),a=null)}if(a)return void this.advanceToChainedBreak(e,a);if(this.currentSelectedFormat=void 0,this.resumeCoordinator.endContinueContentPlayout(),this.restorePictureInPictureToContent(),this.isPlaying=!1,this.currentBreak=null,this.resumeGeneration++,this.effectiveBreakDurationSec=null,g(this.state),this.preloader.clearWarmedBreaks(),this.firstFrameGateActive=!1,this.firstFrameGateShown=!1,this.clearFirstFrame("Break ended before first frame"),"ad"===this.audioFocus&&this.adPlayer?(this.contentPlayer.muted=this.adPlayer.muted,this.contentPlayer.volume=this.adPlayer.volume):"content"===this.audioFocus&&this.adPlayer&&(this.adPlayer.muted=this.contentPlayer.muted,this.adPlayer.volume=this.contentPlayer.volume),this.audioFocus=null,this.clearOverlayImage(),this.vastAdManager?.reset(),this.hide(),this.restoreLayout(s),this.adPlayer?.pause(),this.state.sharedAdClaimActive){const t=this.callbacks;return this.sharedElementPlayer.detachSharedAdListeners(),this.abortingBreak=!1,this.state.earlyReturnResumeOffsetSec=null,this.sharedElementPlayer.restoreSharedElementContent(e),void t?.onBreakEnd(e)}const i="recreate"===this.recoveryDeps.contentRecovery&&"function"==typeof this.contentPlayer.recreateMediaPipeline,n="single-decoder"===this.preloadMode||i?this.adPlayer?.unload?.():void 0;if(this.contentPaused&&r(e))this.contentPaused=!1,this.clearContentGate();else if(this.contentPaused){this.contentPaused=!1,this.clearContentGate(this.resumeHandoverInMotion);const r=this.resumeGeneration;S(this.recoveryDeps,{breakInfo:e,earlyReturnOffsetSec:this.state.earlyReturnResumeOffsetSec,isLiveResume:this.breakTimebase===t.WALLCLOCK,released:n,isCurrent:()=>r===this.resumeGeneration})}this.abortingBreak=!1,this.state.earlyReturnResumeOffsetSec=null,this.callbacks?.onBreakEnd(e)}currentAdAsset(){return this.isPlaying?this.currentAsset:null}skipBreak(){this.isPlaying&&(this.log("Skipping break:",this.currentBreak?.id),M(this.state),this.sequencer&&this.currentBreak?this.drive(this.sequencer.onOutcome({kind:"break-elapsed"})):this.endBreak())}abortBreak(e){this.isPlaying&&(this.log("Early return — break removed from manifest:",this.currentBreak?.id),this.state.earlyReturnResumeOffsetSec=Math.max(0,e),this.abortingBreak=!0,M(this.state),this.sequencer&&this.currentBreak?this.drive(this.sequencer.onOutcome({kind:"break-elapsed"})):this.endBreak())}stopActiveBreak(){g(this.state),this.sharedElementPlayer.cancelSharedRestore()&&this.isPlaying&&(this.log("Aborting active break on session end:",this.currentBreak?.id),M(this.state),this.sharedElementPlayer.detachSharedAdListeners(),this.sharedElementPlayer.releaseContentElementAdPlayer(),this.adPlayer?.pause(),this.clearOverlayImage(),this.vastAdManager?.reset(),this.hide(),this.restoreLayout(this.currentBreak?this.getVariant(this.currentBreak)?.format??void 0:void 0),this.isPlaying=!1,this.currentBreak=null,this.currentAsset=null,this.contentPaused=!1,this.clearContentGate(),this.resumeCoordinator.endContinueContentPlayout(),this.effectiveBreakDurationSec=null,this.firstFrameGateActive=!1,this.firstFrameGateShown=!1,this.clearFirstFrame("Break aborted before first frame"),this.audioFocus=null)}resolveChainedSuccessor(e){return this.breakSequenceDriver.resolveChainedSuccessor(e)}advanceToChainedBreak(e,t){this.breakSequenceDriver.advanceToChainedBreak(e,t)}preloadChainedSuccessor(e){this.preloader.preloadChainedSuccessor(e)}revealFirstFrame(){this.assetPlayback.revealFirstFrame()}armAdStartBudget(e){this.preloader.armAdStartBudget(e)}remainingAdStartBudgetMs(){return this.preloader.remainingAdStartBudgetMs()}loadWithinBudget(e,t){return this.preloader.loadWithinBudget(e,t)}async waitForFirstFrame(){return this.preloader.waitForFirstFrame()}clearFirstFrame(e="Break ended before first frame"){this.preloader.clearFirstFrame(e)}show(){this.adStage.show()}hide(){this.adStage.hide()}isAdPlaying(){return this.isPlaying}get muted(){return"content"===this.audioFocus?this.contentPlayer.muted:"ad"===this.audioFocus?this.adPlayer?this.adPlayer.muted:this.contentPlayer.muted:this.isPlaying&&this.adPlayer?this.adPlayer.muted:this.contentPlayer.muted}set muted(e){if("content"===this.audioFocus)this.contentPlayer.muted=e;else if("ad"===this.audioFocus)this.adPlayer&&(this.adPlayer.muted=e);else{(this.isPlaying&&this.adPlayer?this.adPlayer:this.contentPlayer).muted=e}this.vastAdManager?.setMuted(e),this.notifyVolumeChange()}get volume(){return"content"===this.audioFocus?this.contentPlayer.volume:"ad"===this.audioFocus?this.adPlayer?this.adPlayer.volume:this.contentPlayer.volume:this.isPlaying&&this.adPlayer?this.adPlayer.volume:this.contentPlayer.volume}set volume(e){if("content"===this.audioFocus)this.contentPlayer.volume=e;else if("ad"===this.audioFocus)this.adPlayer&&(this.adPlayer.volume=e);else{(this.isPlaying&&this.adPlayer?this.adPlayer:this.contentPlayer).volume=e}this.vastAdManager?.setVolume(e),this.notifyVolumeChange()}setVolumeChangeCallback(e){this.volumeChangeCallback=e}notifyVolumeChange(){this.volumeChangeCallback?.(this.muted,this.volume)}destroy(){if(this.destroyed)return;if(this.resumeGeneration++,g(this.state),!this.sharedElementPlayer.beginSharedActivity())return;this.destroyed=!0,this.adStage.destroy(),this.resumeCoordinator.cancelResumeLandedProbe(),this.resumeCoordinator.dispose(),this.resumeCoordinator.endResumeCatchup(),this.resumeCoordinator.endContinueContentPlayout(),this.state.resumePrepositionSettle&&(clearTimeout(this.state.resumePrepositionSettle),this.state.resumePrepositionSettle=null),this.releaseContentHold(),this.clearContentGate(),this.clearFirstFrame("Controller destroyed before first frame"),this.firstFrameGateActive=!1,this.firstFrameGateShown=!1,this.resetGamPodTracking(),M(this.state),this.companionRemoveTimer&&(clearTimeout(this.companionRemoveTimer),this.companionRemoveTimer=null),this.adFadeTimer&&(clearTimeout(this.adFadeTimer),this.adFadeTimer=null),this.adPlayer?.pause(),this.clearOverlayImage(),this.pauseAdPresenter.destroy(),this.contentVolumeHandler&&(this.contentPlayer.off("volumechange",this.contentVolumeHandler),this.contentVolumeHandler=null),this.sharedElementPlayer.detachSharedAdListeners(),this.sharedElementPlayer.releaseContentElementAdPlayer(),this.state.pipTransferredToAd=!1,this.teardownFullscreenTracking(),this.teardownPictureInPictureTracking(),this.adVolumeChangeHandler&&this.adPlayer&&this.adPlayer.off("volumechange",this.adVolumeChangeHandler),this.adVolumeChangeHandler=null,this.hide(),this.adStage.destroy(),this.resizeObserver?.disconnect(),this.resizeObserver=null,this.contentVideoMutationObserver?.disconnect(),this.contentVideoMutationObserver=null,this.contentVideoElement&&this.contentVideoGeometryHandler&&(this.contentVideoElement.removeEventListener("loadedmetadata",this.contentVideoGeometryHandler),this.contentVideoElement.removeEventListener("resize",this.contentVideoGeometryHandler)),this.contentVideoElement=null,this.contentVideoGeometryHandler=null;const e=this.adStage.restoreContent(this.playerContainerCreatedBySDK,this.playerContainerOriginalStyle);this.companionElement&&this.companionElement.parentElement&&(this.companionElement.parentElement.removeChild(this.companionElement),this.companionElement=null),this.isPlaying=!1,this.currentBreak=null,this.adContainer&&this.adContainer.parentElement&&this.adContainer.parentElement.removeChild(this.adContainer),!e&&this.stage&&this.stage.parentElement&&this.stage.parentElement.removeChild(this.stage),this.stage=null,this.adContainer=null,this.adMediaContainer=null;try{this.adPlayer?.destroy()}catch(e){this.log("Ad player adapter destroy failed (ignored):",e)}this.adPlayer=null,this.callbacks=null,this.gamPodBridge.destroy(),this.vastAdManager?.destroy(),this.vastAdManager=null,this.log("Ad player destroyed")}log(...e){this.debug&&u("[OptiViewAds:AdPlayerController]",...e)}}AdPlayerController.AD_START_BUDGET_MS=5e3,AdPlayerController.GAM_POD_AD_START_BUDGET_MS=1e4,AdPlayerController.MIN_AD_START_BUDGET_MS=3e3;
|
|
1
|
+
import{BreakFormat as e,Timebase as t,isPostRollBreak as r}from"../types/BreakManifest";import{DEFAULT_AD_BREAK_CUT_SAFETY_MARGIN_SEC as s,DEFAULT_DOUBLE_BOX_AUDIO as a}from"../types/OptiViewAdsConfig";import{pipOverridesFormat as i,pipSuppressesBackdrop as n}from"./pictureInPicture";import{AdBreakSequencer as o,assetsOfVariant as d,resolveBreakFormat as h}from"./AdBreakSequencer";import{selectVariantDetailed as l}from"./selectVariant";import{debugLog as u}from"../diagnostics/debugLog";import{systemClock as c}from"./BreakScheduler";import{createAdPlayerState as m,invalidateMediaPreload as g}from"./adPlayer/AdPlayerState";import{PauseAdPresenter as P}from"./adPlayer/PauseAdPresenter";import{AssetParameterResolver as p}from"./adPlayer/AssetParameterResolver";import{GamPodBridge as y}from"./adPlayer/GamPodBridge";import{AdStage as A}from"./adPlayer/AdStage";import{createDomPresentationHost as C,toPresentationSurfaces as v}from"./adPlayer/presentation/DomPresentationHost";import{AdPreloader as k}from"./adPlayer/AdPreloader";import{PresentationModeTracker as f}from"./adPlayer/PresentationModeTracker";import{SharedElementBreakPlayer as S}from"./adPlayer/SharedElementBreakPlayer";import{ContentResumeCoordinator as B}from"./adPlayer/ContentResumeCoordinator";import{resumeContentAfterBreak as b}from"./adPlayer/ContentRecovery";import{AssetPlayback as E}from"./adPlayer/AssetPlayback";import{SurfaceRevealReporter as T}from"./adPlayer/SurfaceRevealReporter";import{BreakSequenceDriver as M}from"./adPlayer/BreakSequenceDriver";import{VariantSelector as R}from"./adPlayer/VariantSelector";import{AdPlayerEvents as F}from"./adPlayer/AdPlayerEvents";import{AudioController as I}from"./adPlayer/AudioController";import{armPlaybackCutoff as G,clearPlaybackCutoff as w}from"./adPlayer/PlaybackCutoff";import{AdError as D}from"../types/AdError";import{SuccessorQueue as V}from"./adPlayer/SuccessorQueue";export class AdPlayerController{get contentPaused(){return this.state.contentPaused}set contentPaused(e){this.state.contentPaused=e}get firstFrameGateActive(){return this.state.firstFrameGateActive}set firstFrameGateActive(e){this.state.firstFrameGateActive=e}get firstFrameGateShown(){return this.state.firstFrameGateShown}set firstFrameGateShown(e){this.state.firstFrameGateShown=e}get firstFrameRejector(){return this.state.firstFrameRejector}set firstFrameRejector(e){this.state.firstFrameRejector=e}get gamEventCallbacks(){return this.gamPodBridge.eventCallbacks}get vastAdManager(){return this.state.vastAdManager}set vastAdManager(e){this.state.vastAdManager=e}get currentBreak(){return this.state.currentBreak}set currentBreak(e){this.state.currentBreak=e}get currentAsset(){return this.state.currentAsset}set currentAsset(e){this.state.currentAsset=e}get callbacks(){return this.state.callbacks}set callbacks(e){this.state.callbacks=e}get isPlaying(){return this.state.isPlaying}set isPlaying(e){this.state.isPlaying=e}get effectiveBreakDurationSec(){return this.state.effectiveBreakDurationSec}set effectiveBreakDurationSec(e){this.state.effectiveBreakDurationSec=e}get adBreakCutSafetyMarginSec(){return this.state.adBreakCutSafetyMarginSec}set adBreakCutSafetyMarginSec(e){this.state.adBreakCutSafetyMarginSec=e}get durationTimer(){return this.state.durationTimer}set durationTimer(e){this.state.durationTimer=e}get adInsertionType(){return this.state.adInsertionType}set adInsertionType(e){this.state.adInsertionType=e}get breakTimebase(){return this.state.breakTimebase}set breakTimebase(e){this.state.breakTimebase=e}constructor(e,t,r,i,n=!1,o,d="parallel",h="overlay",l=s,u=a,b=!1,G=c,w="none"){this.playerContainerCreatedBySDK=!1,this.adMediaContainer=null,this.adPlayer=null,this.surfaceReveal=new T((e,t,r)=>this.diagnose(e,t,r)),this.adContainer=null,this.companionElement=null,this.staticQuartilesFired=new Set,this.sequencer=null,this.pendingAdError=null,this.preRollHoldActive=!1,this.preRollHoldHandler=null,this.breakContentGateHandler=null,this.destroyed=!1,this.abortingBreak=!1,this.overlayImageEl=null,this.imageAssetTimer=null,this.chainResolver=null,this.transitionPhaseReporter=null,this.chaining=!1,this.diagnoseHandler=null,this.playerContainerOriginalStyle="",this.companionRemoveTimer=null,this.adFadeTimer=null,this.volumeChangeCallback=null,this.stage=null,this.resizeObserver=null,this.contentVideoElement=null,this.contentVideoGeometryHandler=null,this.contentVideoMutationObserver=null,this.resumeGeneration=0,this.singleSurfaceDevice=!1,this.currentSelectedFormat=void 0,this.state=m(),this.state.playerContainer=r??null,this.clock=G,this.singleSurfaceDevice=b,this.contentPlayer=e,this.audio=new I({contentPlayer:e,isAdPlaying:()=>this.isPlaying,getVastAdManager:()=>this.vastAdManager,onVolumeChange:(e,t)=>this.volumeChangeCallback?.(e,t),log:(...e)=>this.log(...e)}),this.adBreakCutSafetyMarginSec=l,this.doubleBoxAudio=u,this.container=t,r&&(this.playerContainer=r),this.createAdAdapter=i,this.debug=n,this.state.gamConfig=o,this.preloadMode=d,this.insertionMode=h,this.pauseAdPresenter=new P({contentPlayer:this.contentPlayer,getStage:()=>this.stage,resolveUri:e=>this.resolveUri(e),buildStaticAssetUrl:(e,t)=>this.buildStaticAssetUrl(e,t),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.assetParameters=new p(this.state,{contentPlayer:this.contentPlayer,container:this.container,getGamStreamManager:()=>this.state.gamStreamManager,getCurrentBreak:()=>this.currentBreak,getEffectiveBreakDuration:()=>this.effectiveBreakDurationSec,diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.gamPodBridge=new y(this.state,{contentPlayer:this.contentPlayer,debug:this.debug,getAdPlayer:()=>this.adPlayer,getAdContainer:()=>this.adContainer,isSharedElement:()=>"shared-element"===this.effectiveInsertionMode(),getCurrentBreak:()=>this.currentBreak,getCurrentAsset:()=>this.currentAsset,getEffectiveBreakDuration:()=>this.effectiveBreakDurationSec,getAdPlayerStreamRemainingSec:()=>this.adPlayerStreamRemainingSec(),emitStep:e=>this.emitStep(e),emitAdStart:(e,t,r,s,a)=>this.callbacks?.onAdStart(e,t,r,s,a),emitAdEnd:(e,t,r,s,a)=>this.callbacks?.onAdEnd(e,t,r,s,a),onAdEnded:()=>this.onAdEnded(),pushAssetParameters:(e,t)=>this.pushAssetParameters(e,t),assetParameterResolver:this.assetParameters,diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.adStage=new A({contentPlayer:this.contentPlayer,container:this.container,getPlayerContainer:()=>this.playerContainer,setPlayerContainer:e=>{this.playerContainer=e},setPlayerContainerOriginalStyle:e=>{this.playerContainerOriginalStyle=e},onPlayerContainerCreated:()=>{this.playerContainerCreatedBySDK=!0},getStage:()=>this.stage,setStage:e=>{this.stage=e},getContentVideo:()=>this.contentVideoElement,setContentVideo:e=>{this.contentVideoElement=e},getAdContainer:()=>this.adContainer,setAdContainer:e=>{this.adContainer=e},getAdMediaContainer:()=>this.adMediaContainer,setAdMediaContainer:e=>{this.adMediaContainer=e},setAdPlayer:e=>{g(this.state),this.adPlayer=e,e&&this.audio.attachAdPlayer(e)},createAdAdapter:e=>this.createAdAdapter(e),setupEventListeners:()=>this.setupEventListeners(),resizeVast:()=>this.vastAdManager?.resize(),getVariant:e=>this.getVariant(e),getCurrentBreak:()=>this.currentBreak,buildStaticAssetUrl:(e,t)=>this.buildStaticAssetUrl(e,t),getCompanion:()=>this.companionElement,setCompanion:e=>{this.companionElement=e},getOverlayImage:()=>this.overlayImageEl,setOverlayImage:e=>{this.overlayImageEl=e},getImageAssetTimer:()=>this.imageAssetTimer,setImageAssetTimer:e=>{this.imageAssetTimer=e},isChaining:()=>this.chaining,log:(...e)=>this.log(...e),presentationHost:C(()=>v(this.playerContainer,this.adContainer,this.stage))}),this.preloader=new k({state:this.state,clock:this.clock,adStartBudgetMs:AdPlayerController.AD_START_BUDGET_MS,gamPodAdStartBudgetMs:AdPlayerController.GAM_POD_AD_START_BUDGET_MS,minAdStartBudgetMs:AdPlayerController.MIN_AD_START_BUDGET_MS,debug:this.debug,isPlaying:()=>this.isPlaying,preloadMode:this.preloadMode,effectiveInsertionMode:()=>this.effectiveInsertionMode(),getVariant:e=>this.getVariant(e),getAssets:e=>this.getAssets(e),buildStaticAssetUrl:(e,t)=>this.buildStaticAssetUrl(e,t),resolveAssetUri:(e,t,r)=>this.resolveAssetUri(e,t,r),getCompanionVariant:e=>this.getVariant(e),getAdPlayer:()=>this.adPlayer,getAdContainer:()=>this.adContainer,buildVastTagUrl:(e,t)=>this.buildVastTagUrl(e,t),resolveChainedSuccessor:e=>this.resolveChainedSuccessor(e),show:()=>this.show(),reapplyAdContainerLayout:e=>this.reapplyAdContainerLayout(e),getCurrentBreak:()=>this.currentBreak,onBreakVisible:e=>this.callbacks?.onBreakVisible?.(e),onAdError:e=>this.onAdError(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.presentationModes=new f(this.state,{contentPlayer:this.contentPlayer,getAdPlayer:()=>this.adPlayer,insertionMode:this.insertionMode,getCurrentBreak:()=>this.currentBreak,getCurrentFormat:()=>this.currentSelectedFormat,isSharedElementActive:()=>this.state.sharedAdClaimActive,getVariant:e=>this.getVariant(e),isAdPlaying:()=>this.isAdPlaying(),hasCurrentAsset:()=>null!==this.currentAsset,contentSourceIsReloadable:()=>null!==this.sharedElementPlayer.restorableContentSource(),adoptPictureInPictureMidBreak:()=>this.adoptPictureInPictureMidBreak(),restoreLayout:()=>this.restoreLayout(),applyLayout:e=>this.applyLayout(e),show:()=>this.show(),playAdThroughContentElement:()=>this.sharedElementPlayer.playAdThroughContentElement(),getContentPositionAtBreakStart:()=>this.state.contentPositionAtBreakStart,setContentPositionAtBreakStart:e=>this.resumeCoordinator.reanchorMidBreak(e),gateContentForBreak:()=>this.gateContentForBreak(),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.resumeCoordinator=new B(this.state,{contentPlayer:this.contentPlayer,clock:this.clock,getInsertionMode:()=>this.effectiveInsertionMode(),gateContentForBreak:()=>this.gateContentForBreak(),clearContentGate:e=>this.clearContentGate(e),muteContent:()=>this.audio.mute("content"),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.recoveryDeps={contentPlayer:e,getCallbacks:()=>this.callbacks,preloadMode:d,contentRecovery:w,resumeCoordinator:this.resumeCoordinator,diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)},this.sharedElementPlayer=new S(this.state,{contentPlayer:this.contentPlayer,getAdPlayer:()=>this.adPlayer,surfaceReveal:this.surfaceReveal,resolveAssetUri:(e,t)=>this.resolveAssetUri(e,t),liveEdgeDistanceSec:()=>this.resumeCoordinator.liveEdgeDistanceSec(),rebindContentElementIfSwapped:()=>this.rebindContentElementIfSwapped(),createAdAdapter:(e,t)=>this.createAdAdapter(e,t),reportAdProgress:e=>this.reportAdProgress(e),processTimedMetadata:e=>this.gamPodBridge.processTimedMetadata(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e),clearContentGate:()=>this.clearContentGate(),hide:()=>this.hide(),waitForLiveEdge:e=>this.resumeCoordinator.waitForLiveEdge(e),getVariant:e=>this.getVariant(e),getAssets:e=>this.getAssets(e)}),this.variantSelector=new R(this.state,{getEffectiveInsertionMode:()=>this.effectiveInsertionMode(),singleSurfaceDevice:this.singleSurfaceDevice,preloadMode:this.preloadMode,getIsContentPictureInPicture:()=>this.isContentPictureInPicture(),getIsGamReady:()=>this.isGamReady(),getSupportsParallelBuffering:()=>this.contentPlayer.supportsParallelBuffering,diagnose:(e,t,r)=>this.diagnose(e,t,r)}),this.successorQueue=new V({getAdPlayer:()=>this.adPlayer,isEnabled:()=>"parallel"===this.preloadMode&&"overlay"===this.effectiveInsertionMode()&&!this.state.sharedAdClaimActive,buildStaticAssetUrl:(e,t)=>this.buildStaticAssetUrl(e,t),getCallbacks:()=>this.state.callbacks,log:(...e)=>this.log(...e)}),this.assetPlayback=new E(this.state,{getAdPlayer:()=>this.adPlayer,getAdContainer:()=>this.adContainer,getAdMediaContainer:()=>this.adMediaContainer,clearStaticQuartiles:()=>this.staticQuartilesFired.clear(),getVariant:e=>this.getVariant(e),getGamEventCallbacks:()=>this.gamEventCallbacks,getSequencer:()=>this.sequencer,debug:this.debug,buildStaticAssetUrl:(e,t)=>this.buildStaticAssetUrl(e,t),buildGamUrl:(e,t)=>this.buildGamUrl(e,t),buildVastTagUrl:(e,t)=>this.buildVastTagUrl(e,t),onAdError:e=>this.onAdError(e),onAdEnded:()=>this.onAdEnded(),drive:e=>this.drive(e),clearOverlayImage:()=>this.clearOverlayImage(),revealFirstFrame:()=>this.preloader.revealFirstFrame(),surfaceReveal:this.surfaceReveal,transferPictureInPictureToAd:()=>this.presentationModes.transferPictureInPictureToAd(),isGamPodAsset:e=>this.isGamPodAsset(e),hasGamIdentityMismatch:e=>this.gamPodBridge.hasIdentityMismatch(e),beginGamPodTracking:e=>this.gamPodBridge.beginGamPodTracking(e),recordAdProgress:e=>this.adPlayerEvents.recordAdProgress(e),reportPhase:e=>this.reportPhase(e),armAdStartBudget:e=>this.armAdStartBudget(e),takeQueuedSuccessor:(e,t,r)=>this.successorQueue.take(e,t,r),queueUpcomingAd:()=>{const e=this.sequencer?.upcomingAsset();e&&this.currentBreak&&this.successorQueue.prepare(this.currentBreak,e,!1)},remainingAdStartBudgetMs:()=>this.remainingAdStartBudgetMs(),loadWithinBudget:(e,t)=>this.loadWithinBudget(e,t),waitForFirstFrame:()=>this.waitForFirstFrame(),getOverlayImage:()=>this.overlayImageEl,setOverlayImage:e=>{this.overlayImageEl=e},getImageAssetTimer:()=>this.imageAssetTimer,setImageAssetTimer:e=>{this.imageAssetTimer=e},getVastPodPosition:()=>this.vastPodPosition,setVastPodPosition:e=>{this.vastPodPosition=e},diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.breakSequenceDriver=new M(this.state,{successorQueue:this.successorQueue,getAssets:e=>this.getAssets(e),getChainResolver:()=>this.chainResolver,getEffectiveInsertionMode:()=>this.effectiveInsertionMode(),getVastPodPosition:()=>this.vastPodPosition,setVastPodPosition:e=>{this.vastPodPosition=e},getPendingAdError:()=>this.pendingAdError,setPendingAdError:e=>{this.pendingAdError=e},getChaining:()=>this.chaining,setChaining:e=>{this.chaining=e},isExpandingPodAsset:e=>this.isExpandingPodAsset(e),fallBackToPodLevelReporting:()=>this.fallBackToPodLevelReporting(),resetGamPodTracking:()=>this.resetGamPodTracking(),emitGamPodSteps:e=>this.gamPodBridge.emitGamPodSteps(e),playAsset:(e,t,r)=>this.playAsset(e,t,r),endBreak:()=>this.endBreak(),playBreak:(e,t,r)=>this.playBreak(e,t,r),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.adPlayerEvents=new F(this.state,{getAdPlayer:()=>this.adPlayer,getContentPlayer:()=>this.contentPlayer,getGamEventCallbacks:()=>this.gamEventCallbacks,getSequencer:()=>this.sequencer,onAdEnded:()=>this.onAdEnded(),processTimedMetadata:e=>this.gamPodBridge.processTimedMetadata(e),toAdError:e=>this.toAdError(e),revealFirstFrame:()=>this.revealFirstFrame(),clearFirstFrameResolver:()=>this.preloader.clearFirstFrameResolver(),drive:e=>this.drive(e),setPendingAdError:e=>{this.pendingAdError=e},dropQueuedAd:()=>this.successorQueue.drop(),log:(...e)=>this.log(...e),maybePrepositionContentForResume:()=>"single-decoder"!==this.preloadMode&&this.resumeCoordinator.maybePrepositionContentForResume(),maybeCatchUpContentForResume:e=>"single-decoder"!==this.preloadMode&&this.resumeCoordinator.maybeCatchUpContentForResume(e),getStaticQuartilesFired:()=>this.staticQuartilesFired,onGamPodAdProgress:e=>this.gamPodBridge.onGamPodAdProgress(e)})}setGamEventCallbacks(e){this.gamPodBridge.setEventCallbacks(e)}setDiagnoseHandler(e){this.diagnoseHandler=e}diagnose(e,t,r){this.diagnoseHandler?.(e,t,r)}holdContentForPreRoll(e){if(this.preRollHoldActive)return;const t=this.getVariant(e);t&&this.shouldPauseContent(t.format)&&(this.preRollHoldActive=!0,this.contentPlayer.pause(),this.preRollHoldHandler=()=>{this.preRollHoldActive&&this.contentPlayer.pause()},this.contentPlayer.on("playing",this.preRollHoldHandler),this.diagnose("DA-PREROLL-CONTENT-HELD","Content held at session start until the pending pre-roll begins.",{breakId:e.id}))}releaseContentHold(){this.preRollHoldActive&&(this.preRollHoldActive=!1,this.preRollHoldHandler&&(this.contentPlayer.off("playing",this.preRollHoldHandler),this.preRollHoldHandler=null))}gateContentForBreak(){this.contentPlayer.pause(),this.breakContentGateHandler||(this.breakContentGateHandler=()=>{this.contentPaused&&!this.state.resumeCatchupActive&&this.contentPlayer.pause()},this.contentPlayer.on("playing",this.breakContentGateHandler))}clearContentGate(e=!1){this.resumeCoordinator.endResumeCatchup(e),this.breakContentGateHandler&&(this.contentPlayer.off("playing",this.breakContentGateHandler),this.breakContentGateHandler=null)}setChainResolver(e){this.chainResolver=e}onChainSuccessorChanged(){this.sequencer&&this.currentBreak&&this.isPlaying&&this.drive(this.sequencer.onOutcome({kind:"successor-changed"}),!0)}setResumeCueAnchorResolver(e){this.resumeCoordinator.setCueAnchorResolver(e)}setResumeCueEndResolver(e){this.resumeCoordinator.setCueEndResolver(e)}ingestStreamClockCue(e){this.resumeCoordinator.ingestStreamClockCue(e)}setTransitionPhaseReporter(e){this.transitionPhaseReporter=e}reportPhase(e){this.transitionPhaseReporter?.(e)}setBreakResumePolicy(e,t,r=!1){this.adInsertionType=e,this.breakTimebase=t,this.state.continueContentDuringBreak=r,this.state.continueRefusalReported=!1}initialize(){this.adContainer||(this.setupOverlay(),this.presentationModes.setupPictureInPictureTracking(),"adaptive"===this.insertionMode&&this.presentationModes.setupFullscreenTracking())}async startGamSession(e,t){await this.gamPodBridge.startGamSession(e,t)}endGamSession(){this.gamPodBridge.endGamSession()}setSessionAssetParameters(e){this.assetParameters.setSessionAssetParameters(e)}setManifestAssetParameters(e){this.assetParameters.setManifestAssetParameters(e)}updateAssetParameters(e){this.assetParameters.updateAssetParameters(e)}resolveExternalVendorConfiguration(e){return this.assetParameters.resolveExternalVendorConfiguration(e)}updateAssetParameterMacros(e){this.assetParameters.updateAssetParameterMacros(e)}get updatedAssetParameters(){return this.state.updatedAssetParameters}setSessionAssetParameterMacros(e){this.assetParameters.setSessionAssetParameterMacros(e)}get sessionAssetParameterMacros(){return this.assetParameters.getSessionAssetParameterMacros()}buildVastTagUrl(e,t){return this.assetParameters.buildVastTagUrl(e,t)}buildStaticAssetUrl(e,t){return this.assetParameters.buildStaticAssetUrl(e,t)}pushAssetParameters(e,t){this.assetParameters.pushAssetParameters(e,t)}setupOverlay(){this.adStage.setupOverlay()}isGamPodAsset(e){return this.gamPodBridge.isGamPodAsset(e)}isExpandingPodAsset(e){return this.gamPodBridge.isExpandingPodAsset(e)}fallBackToPodLevelReporting(){this.gamPodBridge.fallBackToPodLevelReporting()}resetGamPodTracking(){this.gamPodBridge.resetGamPodTracking()}emitGamPodSteps(e){this.gamPodBridge.emitGamPodSteps(e)}isGamEnabled(){return this.gamPodBridge.isGamEnabled()}isGamReady(){return this.gamPodBridge.isGamReady()}isOverlayInsertion(){return"overlay"===this.effectiveInsertionMode()}settleAssetProgress(){this.adPlayerEvents.settleAssetProgress()}reportAdProgress(e){this.adPlayerEvents.reportAdProgress(e)}setupEventListeners(){this.adPlayerEvents.setupEventListeners()}async preload(e){return this.preloader.preload(e)}renderLshapeContentBackdrop(e){this.adStage.renderLshapeContentBackdrop(e)}currentInsertionMode(){return this.presentationModes.currentInsertionMode()}effectiveInsertionMode(){return this.presentationModes.effectiveInsertionMode()}isContentPictureInPicture(){return this.presentationModes.isPictureInPicture()}rebindContentElementIfSwapped(){this.presentationModes.rebindContentElementIfSwapped()}teardownFullscreenTracking(){this.presentationModes.teardownFullscreenTracking()}teardownPictureInPictureTracking(){this.presentationModes.teardownPictureInPictureTracking()}isPictureInPicture(){return this.presentationModes.isPictureInPicture()}pictureInPictureOwner(){return this.presentationModes.pictureInPictureOwner()}isShowingAd(){if(!this.isAdPlaying())return!1;const e=this.currentDeclaredFormat();return!n(e,this.isContentPictureInPicture())}currentDeclaredFormat(){return this.currentSelectedFormat??(this.currentBreak?h(this.currentBreak):void 0)}async playBreak(t,s,a){if(this.state.preloadGeneration++,this.resumeGeneration++,!this.sharedElementPlayer.beginSharedActivity())return;this.releaseContentHold(),this.rebindContentElementIfSwapped();const n=a?.effectiveDurationSec??null;this.effectiveBreakDurationSec=null!==n&&n>0?n:null;const d=this.effectiveBreakDurationSec??t.duration;if("shared-element"===this.effectiveInsertionMode())return g(this.state),void await this.sharedElementPlayer.playSharedElementBreak(t,s);if(!this.adPlayer)return void this.log("playBreak called before initialize()");const h=this.getVariant(t);if(!h)return void this.log("No valid variant found for break:",t.id);this.currentBreak=t,this.callbacks=s,this.isPlaying=!0,this.firstFrameGateActive=a?.firstFrameGate??!1,this.firstFrameGateShown=!1;const l=this.continueContentDuringBreakReason(h.format),u=r(t),c=this.shouldPauseContent(h.format)&&"ok"===l&&!u;c||u||this.state.continueRefusalReported||!this.shouldPauseContent(h.format)||(this.state.continueRefusalReported=!0,this.diagnose("DA-CONTINUE-PLAYOUT-REFUSED",`Content will be paused for breaks this session: ${l}`,{reason:l,format:h.format})),h.format===e.DOUBLE?this.audio.mute("ad"===this.doubleBoxAudio?"content":"ad"):c?this.audio.mute("content"):this.shouldPauseContent(h.format)&&this.audio.unmute("ad");const m=this.declaredFormatOf(t);if(this.currentSelectedFormat=m,this.state.pipAdoptedForBreak=i(m,this.isContentPictureInPicture()),this.state.pipAdoptedForBreak&&this.diagnose("DA-PIP-FORMAT-OVERRIDE",`Picture-in-picture: ${m} break plays as single`,{declared:m,effective:e.SINGLE,reason:"picture-in-picture",midBreak:!1}),this.shouldPauseContent(h.format)?(this.resumeCoordinator.captureBreakAnchor(t),c?(this.contentPaused=!1,this.resumeCoordinator.beginContinueContentPlayout()):(this.contentPaused=!0,this.gateContentForBreak())):this.contentPaused=!1,this.applyLayout(h),h.format===e.LSHAPE_CONTENT)return this.renderLshapeContentBackdrop(h),void(d&&d>0?(this.log("Starting duration timer:",d,"seconds"),this.durationTimer=setTimeout(()=>{this.log("Duration timer expired, ending break"),this.endBreak()},1e3*d)):this.endBreak());this.firstFrameGateActive||(this.show(),this.reapplyAdContainerLayout(h));if(0===this.getAssets(t).length)return this.log("No assets in break, ending immediately"),void this.endBreak();{const e=Math.max(0,d||0)+this.adBreakCutSafetyMarginSec;G(this.state,e,()=>{this.log("Break-cut timer expired, ending break"),this.firstFrameRejector?this.onAdError(new D("Break cut before first frame rendered","DA-AD-START-TIMEOUT")):this.sequencer&&this.currentBreak&&this.isPlaying?(this.callbacks?.onBreakCut?.(this.currentBreak),this.drive(this.sequencer.onOutcome({kind:"break-elapsed"}))):this.endBreak()},()=>this.onAdError(new D("Ad playback startup timed out","DA-AD-START-TIMEOUT")))}this.sequencer=new o("overlay",()=>null,this.selectionInputs(),e=>this.resolveChainedSuccessor(e)),await this.drive(this.sequencer.beginBreak(t)),this.preloadChainedSuccessor(t.id)}get resumeHandoverInMotion(){return this.state.resumeCatchupActive}reapplyAdContainerLayout(e){this.adStage.reapplyAdContainerLayout(e)}adoptPictureInPictureMidBreak(){this.presentationModes.adoptPictureInPictureMidBreak()}async restorePictureInPictureToContent(){await this.presentationModes.restorePictureInPictureToContent()}continueContentDuringBreakReason(e){return this.variantSelector.continueContentDuringBreakReason(e)}shouldPauseContent(t){return t===e.SINGLE||t===e.LSHAPE_AD}selectionInputs(){return this.variantSelector.selectionInputs()}breakNothingToPlayReason(e){return this.variantSelector.breakNothingToPlayReason(e)}unknownVariantFormatsOf(e){return this.variantSelector.unknownVariantFormatsOf(e)}diagnoseUnknownVariantFormats(e){this.variantSelector.diagnoseUnknownVariantFormats(e)}declaredFormatOf(e){const{selected:t,deviceQualified:r}=l(e,this.selectionInputs());return(t??r)?.format??h(e)}getVariant(e){return this.variantSelector.getVariant(e)}applyLayout(e){this.adStage.applyLayout(e)}restoreLayout(){this.adStage.restoreLayout()}getAssets(e){return d(this.getVariant(e))}async playAsset(e,t,r){return this.assetPlayback.playAsset(e,t,r)}clearOverlayImage(){this.adStage.clearOverlayImage()}async showPauseImage(e){return this.pauseAdPresenter.showPauseImage(e)}hidePauseImage(){this.pauseAdPresenter.hidePauseImage()}async drive(e,t=!1){return this.breakSequenceDriver.drive(e,t)}emitStep(e){this.breakSequenceDriver.emitStep(e)}async resolveAssetUri(e,t,r){return this.assetPlayback.resolveAssetUri(e,t,r)}async buildGamUrl(e,t){return this.gamPodBridge.buildGamUrl(e,t)}resolveUri(e){return this.assetParameters.resolveUri(e)}adPlayerStreamRemainingSec(){return this.assetPlayback.adPlayerStreamRemainingSec()}onAdEnded(){this.currentBreak&&this.isPlaying&&this.sequencer&&(this.settleAssetProgress(),this.drive(this.sequencer.onOutcome({kind:"asset-ended"})))}toAdError(e){return this.assetPlayback.toAdError(e)}onAdError(e){this.adPlayerEvents.onAdError(e)}endBreak(){if(!this.currentBreak)return;this.log("Break ended:",this.currentBreak.id),w(this.state),this.state.gamPodTracker&&this.emitGamPodSteps(this.state.gamPodTracker.finish()),this.resetGamPodTracking(),this.pushAssetParameters(void 0);const e=this.currentBreak;let s=this.abortingBreak?null:this.resolveChainedSuccessor(e.id);if(s){const e=this.breakNothingToPlayReason(s);this.diagnoseUnknownVariantFormats(s),e&&(this.diagnose("DA-BREAK-NO-PLAYABLE-ASSET",`chained break ${s.id} has no playable variant (${e}); it will not begin.`,{breakId:s.id,reason:e}),this.callbacks?.onAdError(s,void 0,new D(`Break ${s.id} has no playable variant (${e})`,"DA-BREAK-NO-PLAYABLE-ASSET")),this.callbacks?.onChainedBreakSkipped?.(s),s=null)}if(s)return void this.advanceToChainedBreak(e,s);if(this.currentSelectedFormat=void 0,this.resumeCoordinator.endContinueContentPlayout(),this.restorePictureInPictureToContent(),this.isPlaying=!1,this.currentBreak=null,this.resumeGeneration++,this.effectiveBreakDurationSec=null,g(this.state),this.preloader.clearWarmedBreaks(),this.successorQueue.reset(),this.firstFrameGateActive=!1,this.firstFrameGateShown=!1,this.clearFirstFrame("Break ended before first frame"),this.audio.unmuteAll(),this.clearOverlayImage(),this.vastAdManager?.reset(),this.hide(),this.restoreLayout(),this.adPlayer?.pause(),this.state.sharedAdClaimActive){const t=this.callbacks;return this.sharedElementPlayer.detachSharedAdListeners(),this.abortingBreak=!1,this.state.earlyReturnResumeOffsetSec=null,this.sharedElementPlayer.restoreSharedElementContent(e),void t?.onBreakEnd(e)}const a="recreate"===this.recoveryDeps.contentRecovery&&"function"==typeof this.contentPlayer.recreateMediaPipeline,i="single-decoder"===this.preloadMode||a?this.adPlayer?.unload?.():void 0;if(this.contentPaused&&r(e))this.contentPaused=!1,this.clearContentGate();else if(this.contentPaused){this.contentPaused=!1,this.clearContentGate(this.resumeHandoverInMotion);const r=this.resumeGeneration;b(this.recoveryDeps,{breakInfo:e,earlyReturnOffsetSec:this.state.earlyReturnResumeOffsetSec,isLiveResume:this.breakTimebase===t.WALLCLOCK,released:i,isCurrent:()=>r===this.resumeGeneration})}this.abortingBreak=!1,this.state.earlyReturnResumeOffsetSec=null,this.callbacks?.onBreakEnd(e)}currentAdAsset(){return this.isPlaying?this.currentAsset:null}skipBreak(){this.isPlaying&&(this.log("Skipping break:",this.currentBreak?.id),w(this.state),this.sequencer&&this.currentBreak?this.drive(this.sequencer.onOutcome({kind:"break-elapsed"})):this.endBreak())}abortBreak(e){this.isPlaying&&(this.log("Early return — break removed from manifest:",this.currentBreak?.id),this.state.earlyReturnResumeOffsetSec=Math.max(0,e),this.abortingBreak=!0,w(this.state),this.sequencer&&this.currentBreak?this.drive(this.sequencer.onOutcome({kind:"break-elapsed"})):this.endBreak())}stopActiveBreak(){g(this.state),this.successorQueue.reset(),this.sharedElementPlayer.cancelSharedRestore()&&this.isPlaying&&(this.log("Aborting active break on session end:",this.currentBreak?.id),w(this.state),this.sharedElementPlayer.detachSharedAdListeners(),this.sharedElementPlayer.releaseContentElementAdPlayer(),this.adPlayer?.pause(),this.clearOverlayImage(),this.vastAdManager?.reset(),this.hide(),this.restoreLayout(),this.isPlaying=!1,this.currentBreak=null,this.currentAsset=null,this.contentPaused=!1,this.clearContentGate(),this.resumeCoordinator.endContinueContentPlayout(),this.effectiveBreakDurationSec=null,this.firstFrameGateActive=!1,this.firstFrameGateShown=!1,this.clearFirstFrame("Break aborted before first frame"),this.audio.unmuteAll())}resolveChainedSuccessor(e){return this.breakSequenceDriver.resolveChainedSuccessor(e)}advanceToChainedBreak(e,t){this.breakSequenceDriver.advanceToChainedBreak(e,t)}preloadChainedSuccessor(e){this.preloader.preloadChainedSuccessor(e)}revealFirstFrame(){this.assetPlayback.revealFirstFrame()}armAdStartBudget(e){this.preloader.armAdStartBudget(e)}remainingAdStartBudgetMs(){return this.preloader.remainingAdStartBudgetMs()}loadWithinBudget(e,t){return this.preloader.loadWithinBudget(e,t)}async waitForFirstFrame(){return this.preloader.waitForFirstFrame()}clearFirstFrame(e="Break ended before first frame"){this.preloader.clearFirstFrame(e)}show(){this.adStage.show(),this.surfaceReveal.surfaceShown()}hide(){this.adStage.hide(),this.surfaceReveal.surfaceHidden()}isAdPlaying(){return this.isPlaying}get muted(){return this.audio.muted}set muted(e){this.audio.muted=e}get volume(){return this.audio.volume}set volume(e){this.audio.volume=e}setVolumeChangeCallback(e){this.volumeChangeCallback=e}destroy(){if(this.destroyed)return;if(this.resumeGeneration++,g(this.state),this.successorQueue.reset(),!this.sharedElementPlayer.beginSharedActivity())return;this.destroyed=!0,this.adStage.destroy(),this.resumeCoordinator.cancelResumeLandedProbe(),this.resumeCoordinator.dispose(),this.resumeCoordinator.endResumeCatchup(),this.resumeCoordinator.endContinueContentPlayout(),this.state.resumePrepositionSettle&&(clearTimeout(this.state.resumePrepositionSettle),this.state.resumePrepositionSettle=null),this.releaseContentHold(),this.clearContentGate(),this.clearFirstFrame("Controller destroyed before first frame"),this.firstFrameGateActive=!1,this.firstFrameGateShown=!1,this.resetGamPodTracking(),w(this.state),this.companionRemoveTimer&&(clearTimeout(this.companionRemoveTimer),this.companionRemoveTimer=null),this.adFadeTimer&&(clearTimeout(this.adFadeTimer),this.adFadeTimer=null),this.adPlayer?.pause(),this.clearOverlayImage(),this.pauseAdPresenter.destroy(),this.audio.destroy(),this.sharedElementPlayer.detachSharedAdListeners(),this.sharedElementPlayer.releaseContentElementAdPlayer(),this.state.pipTransferredToAd=!1,this.teardownFullscreenTracking(),this.teardownPictureInPictureTracking(),this.hide(),this.adStage.destroy(),this.resizeObserver?.disconnect(),this.resizeObserver=null,this.contentVideoMutationObserver?.disconnect(),this.contentVideoMutationObserver=null,this.contentVideoElement&&this.contentVideoGeometryHandler&&(this.contentVideoElement.removeEventListener("loadedmetadata",this.contentVideoGeometryHandler),this.contentVideoElement.removeEventListener("resize",this.contentVideoGeometryHandler)),this.contentVideoElement=null,this.contentVideoGeometryHandler=null;const e=this.adStage.restoreContent(this.playerContainerCreatedBySDK,this.playerContainerOriginalStyle);this.companionElement&&this.companionElement.parentElement&&(this.companionElement.parentElement.removeChild(this.companionElement),this.companionElement=null),this.isPlaying=!1,this.currentBreak=null,this.adContainer&&this.adContainer.parentElement&&this.adContainer.parentElement.removeChild(this.adContainer),!e&&this.stage&&this.stage.parentElement&&this.stage.parentElement.removeChild(this.stage),this.stage=null,this.adContainer=null,this.adMediaContainer=null;try{this.adPlayer?.destroy()}catch(e){this.log("Ad player adapter destroy failed (ignored):",e)}this.adPlayer=null,this.callbacks=null,this.gamPodBridge.destroy(),this.vastAdManager?.destroy(),this.vastAdManager=null,this.log("Ad player destroyed")}log(...e){this.debug&&u("[OptiViewAds:AdPlayerController]",...e)}}AdPlayerController.AD_START_BUDGET_MS=5e3,AdPlayerController.GAM_POD_AD_START_BUDGET_MS=1e4,AdPlayerController.MIN_AD_START_BUDGET_MS=3e3;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Break } from '../types/BreakManifest';
|
|
2
|
+
import type { TrackedBreak } from './RewindRearm';
|
|
3
|
+
/**
|
|
4
|
+
* The active break's chained successor appeared, changed or (`null`) disappeared after a
|
|
5
|
+
* manifest update. The renderer re-prepares or drops what it buffered for the switch.
|
|
6
|
+
*/
|
|
7
|
+
export type ChainSuccessorChangedCallback = (activeBreak: Break, successor: Break | null) => void;
|
|
8
|
+
export interface BreakChainDeps {
|
|
9
|
+
breaks: Map<string, TrackedBreak>;
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
maxGapMs: number;
|
|
12
|
+
toleranceMs: number;
|
|
13
|
+
getBreakStartTime: (breakInfo: Break) => number | null;
|
|
14
|
+
log: (...args: unknown[]) => void;
|
|
15
|
+
}
|
|
16
|
+
/** What a renderer buffers for a successor; two breaks with the same signature play the same media. */
|
|
17
|
+
export declare function chainSuccessorSignature(breakInfo: Break): string;
|
|
18
|
+
/**
|
|
19
|
+
* Back-to-back breaks played as one chain: the successors within the chaining gap are CHAINED so
|
|
20
|
+
* the time-based check never starts them on its own, and a manifest update while a break is
|
|
21
|
+
* active re-walks the chain, so a break announced during the chain joins it at once.
|
|
22
|
+
*/
|
|
23
|
+
export declare class BreakChain {
|
|
24
|
+
private readonly deps;
|
|
25
|
+
private onSuccessorChanged;
|
|
26
|
+
/** The successor last seen for the active break; a later manifest update is compared to it. */
|
|
27
|
+
private successorSeen;
|
|
28
|
+
constructor(deps: BreakChainDeps);
|
|
29
|
+
setOnSuccessorChanged(callback: ChainSuccessorChangedCallback | null): void;
|
|
30
|
+
/** Mark every PENDING break that chains after `breakId` as CHAINED. */
|
|
31
|
+
claim(breakId: string): void;
|
|
32
|
+
/** The PENDING/CHAINED break starting within the chaining gap after this break's end, or null. */
|
|
33
|
+
successorOf(breakId: string): Break | null;
|
|
34
|
+
/** Promote a CHAINED (or PENDING) break to ACTIVE as the chain advances into it. */
|
|
35
|
+
activate(breakId: string): void;
|
|
36
|
+
/** After a manifest update: re-walk the chain from the active break and report a changed successor. */
|
|
37
|
+
refresh(active: Break): void;
|
|
38
|
+
private rememberSuccessor;
|
|
39
|
+
/** Claim the breaks now in the chain; release a CHAINED break that moved out of it. */
|
|
40
|
+
private reclaim;
|
|
41
|
+
/** Earliest break starting within the chaining gap after `current`, restricted to `states`. */
|
|
42
|
+
private findSuccessor;
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{BreakState as e}from"./BreakSchedulerTypes";import{variantsOf as s}from"./selectVariant";function t(e){const s=e.uri;return void 0===s?null:"string"==typeof s?s:s.map(e=>e.value)}export function chainSuccessorSignature(e){return JSON.stringify([e.id,e.start,e.duration,s(e).map(e=>[e.format,e.assets.map(e=>[e.id,e.type,t(e),e.duration??null])])])}export class BreakChain{constructor(e){this.deps=e,this.onSuccessorChanged=null,this.successorSeen=null}setOnSuccessorChanged(e){this.onSuccessorChanged=e}claim(s){if(!this.deps.enabled)return;let t=this.deps.breaks.get(s)?.break??null;for(;t;){const s=this.findSuccessor(t,[e.PENDING]);if(!s)break;const i=this.deps.breaks.get(s.id);if(!i||i.state!==e.PENDING)break;i.state=e.CHAINED,this.deps.log(`🔗 Break "${s.id}" claimed as chained after "${t.id}"`),t=s}this.rememberSuccessor(s)}successorOf(s){if(!this.deps.enabled)return null;const t=this.deps.breaks.get(s)?.break;return t?this.findSuccessor(t,[e.PENDING,e.CHAINED]):null}activate(s){const t=this.deps.breaks.get(s);t&&(t.state=e.ACTIVE,this.rememberSuccessor(s))}refresh(e){if(!this.deps.enabled)return;null!==this.deps.getBreakStartTime(e)&&this.reclaim(e);const s=this.successorOf(e.id),t=s?chainSuccessorSignature(s):null,i=this.successorSeen;this.successorSeen={activeId:e.id,signature:t},i?.activeId===e.id&&i.signature!==t&&(this.deps.log(`🔗 Successor of "${e.id}" is now ${s?`"${s.id}"`:"none"}`),this.onSuccessorChanged?.(e,s))}rememberSuccessor(e){const s=this.successorOf(e);this.successorSeen={activeId:e,signature:s?chainSuccessorSignature(s):null}}reclaim(s){const t=new Set;let i=s;for(;i;){const s=this.findSuccessor(i,[e.PENDING,e.CHAINED]);if(!s||t.has(s.id))break;t.add(s.id),i=s}for(const[i,r]of this.deps.breaks)t.has(i)&&r.state===e.PENDING?(r.state=e.CHAINED,this.deps.log(`🔗 Break "${i}" claimed as chained during "${s.id}"`)):t.has(i)||r.state!==e.CHAINED||(r.state=e.PENDING,this.deps.log(`Break "${i}" left the chain of "${s.id}"`))}findSuccessor(e,s){const t=this.deps.getBreakStartTime(e);if(null===t)return null;const i=t+1e3*(e.duration??0);let r=null;for(const n of this.deps.breaks.values()){if(n.break.id===e.id)continue;if(!s.includes(n.state))continue;const a=this.deps.getBreakStartTime(n.break);if(null===a)continue;if(a<=t)continue;const c=a-i;c>this.deps.maxGapMs||(c<-this.deps.toleranceMs||(!r||a<r.start)&&(r={break:n.break,start:a}))}return r?.break??null}}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type Break } from '../types/BreakManifest';
|
|
2
|
+
import { type Clock } from './BreakSchedulerTypes';
|
|
3
|
+
import type { BreakSwitchPath, BreakTransitionMeasurement } from './BreakTransitionTimer';
|
|
4
|
+
/** One break of a chain in a `DA-BREAK-CHAIN` report. */
|
|
5
|
+
export interface ChainBreakEntry {
|
|
6
|
+
id: string;
|
|
7
|
+
/** The manifest `start` (wallclock ISO string or timebase seconds); absent for an event-triggered break. */
|
|
8
|
+
scheduledStart?: string | number;
|
|
9
|
+
plannedDurationSec: number;
|
|
10
|
+
beganAtMs: number;
|
|
11
|
+
endedAtMs?: number;
|
|
12
|
+
/** Seconds from its begin to its end, one decimal. */
|
|
13
|
+
playedSec?: number;
|
|
14
|
+
/** It joined the chain after the chain began (published, or moved into the gap, by a poll). */
|
|
15
|
+
announcedDuringChain: boolean;
|
|
16
|
+
/** How the switch into it went; absent for the chain's first break and when the switch was not measured. */
|
|
17
|
+
path?: BreakSwitchPath;
|
|
18
|
+
}
|
|
19
|
+
/** One measured switch between two breaks of a chain. */
|
|
20
|
+
export interface ChainSwitchEntry {
|
|
21
|
+
toBreakId: string;
|
|
22
|
+
gapMs: number;
|
|
23
|
+
path: BreakSwitchPath;
|
|
24
|
+
leadMs?: number;
|
|
25
|
+
}
|
|
26
|
+
/** The `DA-BREAK-CHAIN` summary of one chain, from its first break's begin to content again. */
|
|
27
|
+
export interface BreakChainReport {
|
|
28
|
+
/** The chain's first break. */
|
|
29
|
+
chainId: string;
|
|
30
|
+
breaks: ChainBreakEntry[];
|
|
31
|
+
switches: ChainSwitchEntry[];
|
|
32
|
+
/** Milliseconds from the last break's end to content playing; absent when content did not resume. */
|
|
33
|
+
contentResumeMs?: number;
|
|
34
|
+
/** Milliseconds from the first break's begin to the last break's end. */
|
|
35
|
+
totalMs: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Collects one chain of breaks and reports it once, when content plays again or the chain is
|
|
39
|
+
* flushed (a new chain begins, the session ends). Fed by the SDK's break lifecycle and by the
|
|
40
|
+
* {@link BreakTransitionTimer} measurements; side-effect free with an injected clock.
|
|
41
|
+
*/
|
|
42
|
+
export declare class BreakChainRecorder {
|
|
43
|
+
private readonly onReport;
|
|
44
|
+
private readonly clock;
|
|
45
|
+
private breaks;
|
|
46
|
+
private switches;
|
|
47
|
+
private knownSuccessorId;
|
|
48
|
+
private announced;
|
|
49
|
+
/** The last break ended; the chain continues only if a chained break begins next. */
|
|
50
|
+
private lastEnded;
|
|
51
|
+
constructor(onReport: (report: BreakChainReport) => void, clock?: Clock);
|
|
52
|
+
/** A break began. A non-chained begin reports any open chain and starts a new one. */
|
|
53
|
+
breakBegan(breakInfo: Break, chained: boolean, knownSuccessorId: string | null): void;
|
|
54
|
+
/** The scheduler reported a new successor of the active break; a new id joined during the chain. */
|
|
55
|
+
successorChanged(successorId: string | null): void;
|
|
56
|
+
breakEnded(breakId: string): void;
|
|
57
|
+
/** A transition measurement: a switch into a chained break, or content playing after the chain. */
|
|
58
|
+
transitionMeasured(measurement: BreakTransitionMeasurement): void;
|
|
59
|
+
/** Report the open chain, if any, without a content resume time. */
|
|
60
|
+
flush(): void;
|
|
61
|
+
private entryFor;
|
|
62
|
+
private emit;
|
|
63
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isEventTrigger as s}from"../types/BreakManifest";import{systemClock as t}from"./BreakSchedulerTypes";export class BreakChainRecorder{constructor(s,e=t){this.onReport=s,this.clock=e,this.breaks=[],this.switches=[],this.knownSuccessorId=null,this.announced=new Set,this.lastEnded=!1}breakBegan(t,e,n){e||this.flush();const i=t.start;this.breaks.push({id:t.id,...s(i)?{}:{scheduledStart:i},plannedDurationSec:t.duration,beganAtMs:this.clock.now(),announcedDuringChain:e&&this.announced.has(t.id)}),this.knownSuccessorId=n,this.lastEnded=!1}successorChanged(s){this.breaks.length>0&&null!==s&&s!==this.knownSuccessorId&&this.announced.add(s),this.knownSuccessorId=s}breakEnded(s){const t=this.entryFor(s);if(!t||void 0!==t.endedAtMs)return;const e=this.clock.now();t.endedAtMs=e,t.playedSec=Math.round(Math.max(0,e-t.beganAtMs)/100)/10,this.lastEnded=!0}transitionMeasured(s){if("break-to-break"===s.kind){const t=this.entryFor(s.breakId);if(!t)return;const e=s.path??"cold";t.path=e,this.switches.push({toBreakId:s.breakId,gapMs:s.durationMs,path:e,...void 0!==s.leadMs?{leadMs:s.leadMs}:{}})}else"out-of-break"===s.kind&&this.lastEnded&&this.emit(s.durationMs)}flush(){this.breaks.length>0&&this.emit(void 0)}entryFor(s){for(let t=this.breaks.length-1;t>=0;t--)if(this.breaks[t].id===s)return this.breaks[t]}emit(s){const t=this.breaks[0],e=this.breaks[this.breaks.length-1].endedAtMs??this.clock.now(),n={chainId:t.id,breaks:this.breaks,switches:this.switches,...void 0!==s?{contentResumeMs:s}:{},totalMs:Math.max(0,e-t.beganAtMs)};this.breaks=[],this.switches=[],this.knownSuccessorId=null,this.announced=new Set,this.lastEnded=!1,this.onReport(n)}}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare class BreakPreloadLedger {
|
|
2
|
+
private readonly preloadedBreakIds;
|
|
3
|
+
private readonly rejectedBreakIds;
|
|
4
|
+
private retryRejectedPreloadsAtStart;
|
|
5
|
+
wasPreloaded(breakId: string): boolean;
|
|
6
|
+
wasRejected(breakId: string): boolean;
|
|
7
|
+
shouldRetryRejectedAtStart(breakId: string): boolean;
|
|
8
|
+
checkAtBreakStart(wasHeld: boolean, check: () => void): void;
|
|
9
|
+
recordAttempt(breakId: string, accepted: boolean): void;
|
|
10
|
+
deletePreloaded(breakId: string): void;
|
|
11
|
+
delete(breakId: string): void;
|
|
12
|
+
clear(): void;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export class BreakPreloadLedger{constructor(){this.preloadedBreakIds=new Set,this.rejectedBreakIds=new Set,this.retryRejectedPreloadsAtStart=!1}wasPreloaded(e){return this.preloadedBreakIds.has(e)}wasRejected(e){return this.rejectedBreakIds.has(e)}shouldRetryRejectedAtStart(e){return this.retryRejectedPreloadsAtStart&&this.wasRejected(e)}checkAtBreakStart(e,t){this.retryRejectedPreloadsAtStart=e;try{t()}finally{this.retryRejectedPreloadsAtStart=!1}}recordAttempt(e,t){t?(this.rejectedBreakIds.delete(e),this.preloadedBreakIds.add(e)):this.rejectedBreakIds.add(e)}deletePreloaded(e){this.preloadedBreakIds.delete(e)}delete(e){this.deletePreloaded(e),this.rejectedBreakIds.delete(e)}clear(){this.preloadedBreakIds.clear(),this.rejectedBreakIds.clear()}}
|
|
@@ -3,8 +3,10 @@ import type { AdBreakSkipReason } from '../types/Events';
|
|
|
3
3
|
import { Break, BreakManifest } from '../types/BreakManifest';
|
|
4
4
|
import { type ResolvedBreakWarnings } from '../types/OptiViewAdsConfig';
|
|
5
5
|
import type { MetadataCueTracker } from './MetadataCueTracker';
|
|
6
|
+
import { type ChainSuccessorChangedCallback } from './BreakChain';
|
|
6
7
|
import { type BreakAbortedCallback, type BreakApproachingCallback, type BreakStartCallback, type BreakWarningCallback, type Clock, type SchedulerDiagnose, type TuneInOptions } from './BreakSchedulerTypes';
|
|
7
8
|
export { BreakState, systemClock, type BreakAbortedCallback, type BreakApproachingCallback, type BreakStartCallback, type BreakStartContext, type BreakWarningCallback, type Clock, type SchedulerDiagnose, type TuneInOptions, } from './BreakSchedulerTypes';
|
|
9
|
+
export type { ChainSuccessorChangedCallback } from './BreakChain';
|
|
8
10
|
/** Scheduling cadence; a break is discovered up to one interval late on the tick alone. */
|
|
9
11
|
export declare const TICK_INTERVAL_MS = 250;
|
|
10
12
|
export declare class BreakScheduler {
|
|
@@ -27,12 +29,13 @@ export declare class BreakScheduler {
|
|
|
27
29
|
private onBreakWarning;
|
|
28
30
|
private onBreakAborted;
|
|
29
31
|
private onBreakSkipped;
|
|
32
|
+
private beforeBreakCheck;
|
|
30
33
|
private breakStartsHeld;
|
|
34
|
+
private readonly preloadLedger;
|
|
31
35
|
private onAdStartDelayElapsed;
|
|
32
36
|
private adStartDelayElapsedNotified;
|
|
33
37
|
/** Break ids whose early-return abort was already notified; polls keep arriving during the teardown. */
|
|
34
38
|
private abortNotifiedBreakIds;
|
|
35
|
-
private preloadedBreakIds;
|
|
36
39
|
private breakWarnings;
|
|
37
40
|
/** Warning thresholds already fired per break, so each `breakWarnings.seconds` value emits once. */
|
|
38
41
|
private breakWarningFired;
|
|
@@ -46,8 +49,7 @@ export declare class BreakScheduler {
|
|
|
46
49
|
/** Wallclock instant content playback ended (spec `event: 'end'`), or null while content plays. */
|
|
47
50
|
private playbackEndedAtMs;
|
|
48
51
|
private debug;
|
|
49
|
-
private
|
|
50
|
-
private maxChainGapMs;
|
|
52
|
+
private readonly chain;
|
|
51
53
|
private tuneInEnabled;
|
|
52
54
|
private minBreakDurationMs;
|
|
53
55
|
private clock;
|
|
@@ -97,9 +99,11 @@ export declare class BreakScheduler {
|
|
|
97
99
|
getChainedSuccessor(breakId: string): Break | null;
|
|
98
100
|
/** Promote a CHAINED (or PENDING) break to ACTIVE as the chain advances, so completeBreak() cleans it up. */
|
|
99
101
|
activateChainedBreak(breakId: string): void;
|
|
100
|
-
/**
|
|
101
|
-
|
|
102
|
+
/** Notified when a manifest update adds, changes or removes the active break's chained successor. */
|
|
103
|
+
setOnChainSuccessorChanged(callback: ChainSuccessorChangedCallback | null): void;
|
|
102
104
|
updateManifest(manifest: BreakManifest): void;
|
|
105
|
+
applyEventBoundary(manifest: BreakManifest): void;
|
|
106
|
+
setEventBoundaryCheck(check: ((positionMs: number | null) => boolean) | null): void;
|
|
103
107
|
/**
|
|
104
108
|
* Re-align the schedule to a manifest from a different channel (see `detectChannelSwitch`).
|
|
105
109
|
* Every ledger of the previous channel is dropped so a break id reused by the new channel
|
|
@@ -139,6 +143,11 @@ export declare class BreakScheduler {
|
|
|
139
143
|
*/
|
|
140
144
|
private armStartDeadline;
|
|
141
145
|
private clearStartDeadline;
|
|
146
|
+
/** Halt the tick, keeping tracked breaks and callbacks; {@link resume} restarts it. */
|
|
147
|
+
suspend(): void;
|
|
148
|
+
resume(): void;
|
|
149
|
+
/** Retire the PENDING breaks that started while another stream played; returns their ids. */
|
|
150
|
+
skipPendingBreaksDueBy(reason: AdBreakSkipReason): string[];
|
|
142
151
|
stop(): void;
|
|
143
152
|
completeBreak(breakId: string): void;
|
|
144
153
|
/** Bracket a content RELOAD so the new stream's start is not read as a backward seek. `false` also discards the stale previous position. */
|
|
@@ -159,6 +168,11 @@ export declare class BreakScheduler {
|
|
|
159
168
|
getActiveBreak(): Break | null;
|
|
160
169
|
/** Rounded seconds until a PENDING break starts, or `null`; refreshes the `upcoming` countdown without polling events. */
|
|
161
170
|
getSecondsUntilBreak(breakId: string): number | null;
|
|
171
|
+
/** The PENDING break starting soonest (ties: smaller id) with the seconds until it; null when none has a known start. */
|
|
172
|
+
getNextPendingBreak(): {
|
|
173
|
+
id: string;
|
|
174
|
+
secondsUntil: number;
|
|
175
|
+
} | null;
|
|
162
176
|
/**
|
|
163
177
|
* Advance the schedule NOW because a cue reached the playhead: the 250ms tick discovers a start
|
|
164
178
|
* ~125ms late on average, an adapter reporting PRESENTATION knows the instant. Runs
|
|
@@ -178,7 +192,7 @@ export declare class BreakScheduler {
|
|
|
178
192
|
/** While true no break may start and consumers must not apply break-driven restrictions (e.g. pause ads). */
|
|
179
193
|
isAdStartDelayActive(): boolean;
|
|
180
194
|
private getCurrentTime;
|
|
181
|
-
/**
|
|
195
|
+
/** Retry rejected callbacks; an accepted preload fires at most once per break. */
|
|
182
196
|
private maybePreload;
|
|
183
197
|
private getBreakStartTime;
|
|
184
198
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BreakEvent as e,Timebase as t,getBreakEvent as i,getPostRollDelay as a,getPreRollDelay as s,isEventTrigger as r,isPauseBreak as n}from"../types/BreakManifest";import{DEFAULT_BREAK_WARNINGS as d,DEFAULT_PDT_GRACE_SECONDS as l}from"../types/OptiViewAdsConfig";import{PTS_MATCH_TOLERANCE_SECONDS as h}from"./MetadataCueTracker";import{debugLog as o}from"../diagnostics/debugLog";import{createBreakTimingState as k,describeBreakStart as c,diagnoseAnvatoBreakEnd as u,getBreakStartTime as b,getCurrentTime as g,secondsUntilBreak as S}from"./breakTiming";import{RewindRearm as m}from"./RewindRearm";import{BreakState as p,systemClock as B}from"./BreakSchedulerTypes";export{BreakState,systemClock}from"./BreakSchedulerTypes";export const TICK_INTERVAL_MS=250;export class BreakScheduler{constructor(e,t=!1,i={enabled:!1,maxGapSeconds:0},a=B,s={enabled:!1,minBreakDurationSeconds:0},r=null,n=d,h=null,o=l){this.breaks=new Map,this.timing=k(),this.checkInterval=null,this.startDeadline=null,this.nextStartDeadlineMs=null,this.onBreakStart=null,this.onBreakApproaching=null,this.onBreakWarning=null,this.onBreakAborted=null,this.onBreakSkipped=null,this.breakStartsHeld=!1,this.onAdStartDelayElapsed=null,this.adStartDelayElapsedNotified=!1,this.abortNotifiedBreakIds=new Set,this.preloadedBreakIds=new Set,this.breakWarnings=d,this.breakWarningFired=new Map,this.completedBreakIds=new Set,this.unsupportedEventBreakIds=new Set,this.playbackEndedAtMs=null,this.anvatoEnteredDiagnosed=new Set,this.retiredBreaks=new Map,this.minSeenTime=null,this.JOIN_DISCRIMINATOR_SLACK_MS=1e3,this.WINDOW_ESCAPE_GRACE_MS=12e3,this.TIMING_TOLERANCE_MS=5e3,this.PRELOAD_AHEAD_SECONDS=8,this.contentReloading=!1,this.startupSeeking=!1,this.player=e,this.debug=t,this.chainingEnabled=i.enabled,this.maxChainGapMs=1e3*Math.max(0,i.maxGapSeconds),this.tuneInEnabled=s.enabled,this.minBreakDurationMs=1e3*Math.max(0,s.minBreakDurationSeconds),this.clock=a,this.diagnose=r,this.breakWarnings=n,this.cueTracker=h;const c=Math.max(0,o);this.timingDeps={player:this.player,clock:this.clock,cueTracker:this.cueTracker,diagnose:this.diagnose,log:(...e)=>this.log(...e),pdtGraceSeconds:c,pdtGraceMs:1e3*c},this.rewind=new m({breaks:this.breaks,retiredBreaks:this.retiredBreaks,completedBreakIds:this.completedBreakIds,preloadedBreakIds:this.preloadedBreakIds,timing:this.timing,clock:this.clock,log:(...e)=>this.log(...e),getBreakStartTime:e=>this.getBreakStartTime(e)})}claimChain(e){if(!this.chainingEnabled)return;let t=this.breaks.get(e)?.break??null;for(;t;){const e=this.findSuccessor(t);if(!e)break;const i=this.breaks.get(e.id);if(!i||i.state!==p.PENDING)break;i.state=p.CHAINED,this.log(`🔗 Break "${e.id}" claimed as chained after "${t.id}"`),t=e}}getChainedSuccessor(e){if(!this.chainingEnabled)return null;const t=this.breaks.get(e)?.break;return t?this.findSuccessor(t,[p.PENDING,p.CHAINED]):null}activateChainedBreak(e){const t=this.breaks.get(e);t&&(t.state=p.ACTIVE)}findSuccessor(e,t=[p.PENDING]){const i=this.getBreakStartTime(e);if(null===i)return null;const a=i+1e3*(e.duration??0);let s=null;for(const r of this.breaks.values()){if(r.break.id===e.id)continue;if(!t.includes(r.state))continue;const n=this.getBreakStartTime(r.break);if(null===n)continue;if(n<=i)continue;const d=n-a;d>this.maxChainGapMs||(d<-this.TIMING_TOLERANCE_MS||(!s||n<s.start)&&(s={break:r.break,start:n}))}return s?.break??null}updateManifest(e){this.timing.timebase=e.timebase;const t=this.rewind.adStartDelayMs;this.rewind.setAdStartDelayMs(1e3*Math.max(0,e.adStartDelay??0)),t>0&&0===this.rewind.adStartDelayMs&&this.notifyAdStartDelayElapsed();for(const t of e.breaks){if(n(t))continue;if(!this.isSchedulableEvent(t))continue;if(this.completedBreakIds.has(t.id))continue;const e=this.breaks.get(t.id);e?e.state===p.PENDING&&(e.break=t):(this.breaks.set(t.id,{break:t,state:p.PENDING}),this.log(`📅 Break scheduled: "${t.id}" at ${c(t)}`))}const i=new Set(e.breaks.map(e=>e.id));for(const[e,t]of this.breaks)i.has(e)||t.state!==p.ACTIVE||this.abortNotifiedBreakIds.has(e)||(this.abortNotifiedBreakIds.add(e),this.log("Break removed from manifest while active (early return):",e),this.diagnose?.("DA-BREAK-EARLY-RETURN","Active break removed from manifest; returning to content early",{breakId:e}),this.onBreakAborted?.(t.break));this.cleanupBreaks(i)}resetForChannelSwitch(e){const t=this.getActiveBreak();for(const e of[...this.breaks.keys()])e!==t?.id&&this.breaks.delete(e);for(const e of[...this.abortNotifiedBreakIds])e!==t?.id&&this.abortNotifiedBreakIds.delete(e);this.completedBreakIds.clear(),this.retiredBreaks.clear(),this.preloadedBreakIds.clear(),this.breakWarningFired.clear(),this.unsupportedEventBreakIds.clear(),this.anvatoEnteredDiagnosed.clear(),this.timing.anvatoPendingDiagnosed.clear(),this.timing.anvatoMatchedDiagnosed.clear(),this.timing.anvatoEndDiagnosed.clear(),this.playbackEndedAtMs=null,this.rewind.beginChannel();const i=t?{...e,breaks:e.breaks.filter(e=>e.id!==t.id)}:e;this.updateManifest(i)}isSchedulableEvent(t){return!r(t.start)||t.start.event===e.START||t.start.event===e.END||(this.unsupportedEventBreakIds.has(t.id)||(this.unsupportedEventBreakIds.add(t.id),this.log(`⚠️ Break ignored: "${t.id}" (unsupported event trigger "${t.start.event}")`),this.diagnose?.("DA-BREAK-EVENT-UNSUPPORTED","Break triggered by an event this SDK version does not schedule; the break was ignored",{breakId:t.id,event:t.start.event})),!1)}markPlaybackStart(){null!==this.playbackEndedAtMs&&(this.playbackEndedAtMs=null,this.log("Content replayed; pending post-rolls cancelled")),this.rewind.playbackStarted||(this.rewind.markPlaybackStart(this.peekPosition()),this.log("Content playback started at",new Date(this.clock.now()).toISOString()))}setOnAdStartDelayElapsed(e){this.onAdStartDelayElapsed=e}holdBreakStarts(){this.breakStartsHeld=!0}releaseBreakStarts(){this.breakStartsHeld=!1,this.checkBreaks()}areBreakStartsHeld(){return this.breakStartsHeld||this.rewind.isAdStartDelayActive()}notifyAdStartDelayElapsed(){this.adStartDelayElapsedNotified||(this.adStartDelayElapsedNotified=!0,this.onAdStartDelayElapsed?.())}markPlaybackEnd(){null===this.playbackEndedAtMs&&(this.playbackEndedAtMs=this.clock.now(),this.log("Content playback ended at",new Date(this.playbackEndedAtMs).toISOString()))}start(e,t,i,a,s){this.onBreakStart=e,this.onBreakApproaching=t??null,this.onBreakWarning=i??null,this.onBreakAborted=a??null,this.onBreakSkipped=s??null,this.checkInterval&&clearInterval(this.checkInterval),this.checkInterval=setInterval(()=>{this.tick()},250),this.log("Scheduler started")}tick(){this.checkBreaks(),null!==this.nextStartDeadlineMs&&this.armStartDeadline(this.nextStartDeadlineMs)}armStartDeadline(e){null!==this.checkInterval&&null===this.startDeadline&&(this.startDeadline=setTimeout(()=>{this.startDeadline=null,this.tick()},Math.max(1,Math.ceil(e))))}clearStartDeadline(){this.startDeadline&&clearTimeout(this.startDeadline),this.startDeadline=null}stop(){this.checkInterval&&(clearInterval(this.checkInterval),this.checkInterval=null),this.clearStartDeadline(),this.onBreakStart=null,this.onBreakSkipped=null,this.log("Scheduler stopped")}completeBreak(e){this.completedBreakIds.add(e),this.breakWarningFired.delete(e),this.abortNotifiedBreakIds.delete(e);const t=this.breaks.get(e);t&&(this.log("Break completed and removed:",e),null===i(t.break)&&null===this.cueTracker&&this.retiredBreaks.set(e,t.break),this.breaks.delete(e),this.preloadedBreakIds.delete(e))}setContentReloading(e){this.contentReloading=e,this.rewind.setContentReloading(e||this.startupSeeking)}setStartupSeeking(e){this.startupSeeking=e,this.rewind.setContentReloading(e||this.contentReloading)}notifyResumeSeek(e,t){this.rewind.notifyResumeSeek(e,t)}notifyViewerSeek(){this.rewind.notifyViewerSeek()}skipBreak(e,t){e.state=p.SKIPPED,this.completedBreakIds.add(e.break.id),this.onBreakSkipped?.(e.break,t)}cleanupBreaks(e){const t=[];for(const[i,a]of this.breaks)a.state!==p.COMPLETED&&a.state!==p.SKIPPED?e.has(i)||a.state===p.ACTIVE||(this.skipBreak(a,"removed"),t.push(i)):t.push(i);for(const e of t)this.breaks.delete(e),this.preloadedBreakIds.delete(e),this.breakWarningFired.delete(e)}getActiveBreak(){for(const e of this.breaks.values())if(e.state===p.ACTIVE)return e.break;return null}getSecondsUntilBreak(e){const t=this.breaks.get(e);if(!t||t.state!==p.PENDING)return null;const i=this.getCurrentTime();if(null===i)return null;const a=this.getBreakStartTime(t.break);return null===a?null:S(a,i)}notifyCuePresented(e){if(null===this.cueTracker||this.timing.timebase!==t.PTS)return null;if(!Number.isFinite(e))return null;let i=null;for(const t of this.breaks.values())if(t.state===p.PENDING&&"number"==typeof t.break.start&&!(Math.abs(t.break.start-e)>h)){i=t.break.id;break}if(null===i)return null;const a=this.player.currentTime;this.checkBreaks();const s=this.breaks.get(i);return s&&s.state===p.ACTIVE?this.anvatoEnteredDiagnosed.has(i)?null:(this.anvatoEnteredDiagnosed.add(i),this.log(`🎯 Break "${i}" armed by cue presentation (pts ${e})`),this.diagnose?.("DA-ANVATO-CUE-ENTERED",`Break "${i}" started from the presented cue (pts ${e}) rather than the scheduler tick.`,{breakId:i,pts:e,mediaTimeSec:a}),i):null}checkBreaks(){if(this.nextStartDeadlineMs=null,this.startupSeeking)return;const e=this.getCurrentTime();this.rewind.trackPlayedTime(e),this.rewind.adStartDelayMs>0&&!this.rewind.isAdStartDelayActive()&&this.notifyAdStartDelayElapsed();const i=this.areBreakStartsHeld();null!==e&&(this.minSeenTime=null===this.minSeenTime?e:Math.min(this.minSeenTime,e),this.rewind.rearmOnRewind(e));for(const r of this.breaks.values()){if(r.state===p.ACTIVE&&this.timing.timebase===t.WALLCLOCK&&null!==e&&!this.abortNotifiedBreakIds.has(r.break.id)){const t=this.getBreakStartTime(r.break),i=1e3*(r.break.duration??0);null!==t&&i>0&&e>t+i+this.WINDOW_ESCAPE_GRACE_MS&&(this.abortNotifiedBreakIds.add(r.break.id),this.log(`⚠️ Break window escaped: "${r.break.id}" (ended ${Math.round((e-t-i)/1e3)}s ago on the stream clock)`),this.diagnose?.("DA-BREAK-WINDOW-ESCAPED","Active break outlived its wallclock window; returning to content",{breakId:r.break.id,overrunSec:Math.round((e-t-i)/100)/10}),this.onBreakAborted?.(r.break));continue}if(r.state===p.ACTIVE&&this.timing.timebase===t.PTS&&u(this.timing,this.timingDeps,r.break),r.state!==p.PENDING)continue;const n=s(r.break);if(null!==n){this.checkPreRollBreak(r,n,i);continue}const d=a(r.break);if(null!==d){this.checkPostRollBreak(r,d,i);continue}if(null===e)continue;if(i)continue;null!==this.cueTracker&&this.timing.timebase===t.PTS&&this.maybePreload(r.break,"manifest arrival — Anvato flow");const l=this.getBreakStartTime(r.break);if(null===l)continue;const h=e-l,o=Math.round(-h/1e3);if(this.timing.timebase===t.WALLCLOCK&&h<0&&-h<=250&&(this.nextStartDeadlineMs=Math.min(this.nextStartDeadlineMs??1/0,-h)),this.checkWarnings(r.break,o),o>0&&o<=15&&o%2==0&&this.log(`⏱️ Break "${r.break.id}" starts in ${o}s`),o>0&&o<=this.PRELOAD_AHEAD_SECONDS&&this.maybePreload(r.break,`${o}s ahead`),h>=0&&h<=this.TIMING_TOLERANCE_MS){const e=Math.max(0,h),t=1e3*(r.break.duration??0)-e;if(t<=0){this.log(`⚠️ Break missed: "${r.break.id}" (ended ${Math.round(-t/1e3)}s ago, inside the start tolerance)`),this.skipBreak(r,t>0&&this.tuneInEnabled?"insufficient-remaining":"late"),null===this.cueTracker&&this.breaks.get(r.break.id)===r&&this.retiredBreaks.set(r.break.id,r.break);break}if(null!==this.minSeenTime&&l<this.minSeenTime-this.JOIN_DISCRIMINATOR_SLACK_MS&&(!this.tuneInEnabled||t<this.minBreakDurationMs)){this.log(`⚠️ Break missed: "${r.break.id}" (joined in progress inside the start tolerance, ${Math.round(t/1e3)}s remaining < tune-in rules)`),this.skipBreak(r,t>0&&this.tuneInEnabled?"insufficient-remaining":"late"),null===this.cueTracker&&this.breaks.get(r.break.id)===r&&this.retiredBreaks.set(r.break.id,r.break);break}this.log(`🎬 BREAK TRIGGERED: "${r.break.id}"`),r.state=p.ACTIVE,this.onBreakStart&&this.onBreakStart(r.break,{tuneIn:!1,elapsedSec:e/1e3,remainingSec:t/1e3});break}if(h>this.TIMING_TOLERANCE_MS){const t=l+1e3*(r.break.duration??0)-e;if(this.tuneInEnabled&&t>=this.minBreakDurationMs&&t>0){this.log(`🎬 TUNE-IN BREAK TRIGGERED: "${r.break.id}" (${Math.round(t/1e3)}s remaining)`),r.state=p.ACTIVE,this.onBreakStart&&this.onBreakStart(r.break,{tuneIn:!0,elapsedSec:h/1e3,remainingSec:t/1e3});break}this.log(`⚠️ Break missed: "${r.break.id}" (was ${Math.round(h/1e3)}s ago)`),this.skipBreak(r,t>0&&this.tuneInEnabled?"insufficient-remaining":"late"),null===this.cueTracker&&this.breaks.get(r.break.id)===r&&this.retiredBreaks.set(r.break.id,r.break)}}}checkPreRollBreak(e,t,i){if(!this.rewind.playbackStarted)return;const a=1e3*t;if(this.rewind.adStartDelayMs>0&&a<this.rewind.adStartDelayMs)return this.log(`⚠️ Pre-roll skipped: "${e.break.id}" (delay ${t}s < adStartDelay ${this.rewind.adStartDelayMs/1e3}s)`),void this.skipBreak(e,"start-delay");const s=this.rewind.channelPlayedMs,r=Math.round((a-s)/1e3);r>0&&r<=15&&r%2==0&&this.log(`⏱️ Pre-roll "${e.break.id}" starts in ${r}s`),r>0&&r<=this.PRELOAD_AHEAD_SECONDS&&this.maybePreload(e.break,`pre-roll, ${r}s ahead`),s>=a&&!i&&(this.log(`🎬 PRE-ROLL TRIGGERED: "${e.break.id}"${t>0?` (after ${t}s delay)`:""}`),e.state=p.ACTIVE,this.onBreakStart&&this.onBreakStart(e.break,{tuneIn:!1,elapsedSec:0,remainingSec:e.break.duration??0}))}checkPostRollBreak(e,t,i){if(null===this.playbackEndedAtMs)return;const a=1e3*t,s=this.clock.now()-this.playbackEndedAtMs,r=Math.round((a-s)/1e3);r>0&&r<=this.PRELOAD_AHEAD_SECONDS&&this.maybePreload(e.break,`post-roll, ${r}s ahead`),s>=a&&!i&&(this.log(`🎬 POST-ROLL TRIGGERED: "${e.break.id}"${t>0?` (after ${t}s delay)`:""}`),e.state=p.ACTIVE,this.onBreakStart&&this.onBreakStart(e.break,{tuneIn:!1,elapsedSec:0,remainingSec:e.break.duration??0}))}isAdStartDelayActive(){return this.areBreakStartsHeld()}getCurrentTime(){return g(this.timing,this.timingDeps)}maybePreload(e,t){if(this.preloadedBreakIds.has(e.id)||!this.onBreakApproaching)return;this.log(`⏳ Preloading break "${e.id}" (${t})`);!1!==this.onBreakApproaching(e)&&this.preloadedBreakIds.add(e.id)}getBreakStartTime(e){return r(e.start)?null:b(this.timing,this.timingDeps,e)}peekPosition(){if(this.timing.timebase!==t.WALLCLOCK)return 1e3*this.player.currentTime;const e=this.player.programDateTime?.getTime();return void 0===e||isNaN(e)?null:e}destroy(){this.stop(),this.breaks.clear(),this.preloadedBreakIds.clear(),this.completedBreakIds.clear(),this.retiredBreaks.clear(),this.minSeenTime=null,this.breakStartsHeld=!1,this.onAdStartDelayElapsed=null,this.adStartDelayElapsedNotified=!1,this.unsupportedEventBreakIds.clear(),this.playbackEndedAtMs=null,this.rewind.reset(),this.breakWarningFired.clear(),this.abortNotifiedBreakIds.clear(),this.timing.pdtMissingWarned=!1,this.timing.pdtSeen=!1,this.timing.firstPdtAttemptMs=null,this.timing.playbackStartedAtMs=null,this.timing.anvatoPendingDiagnosed.clear(),this.timing.anvatoMatchedDiagnosed.clear(),this.timing.anvatoEndDiagnosed.clear(),this.cueTracker?.clear()}checkWarnings(e,t){if(t<=0||0===this.breakWarnings.seconds.length)return;let i=this.breakWarningFired.get(e.id);i||(i=new Set,this.breakWarningFired.set(e.id,i));for(const a of this.breakWarnings.seconds)i.has(a)||t<=a&&(i.add(a),this.log(`Break warning for "${e.id}" (${t}s <= ${a}s)`),this.onBreakWarning?.(e,a,t))}log(...e){this.debug&&o("[OptiViewAds:BreakScheduler]",...e)}}
|
|
1
|
+
import{BreakEvent as e,Timebase as t,getBreakEvent as a,getPostRollDelay as i,getPreRollDelay as r,isEventTrigger as s,isPauseBreak as n}from"../types/BreakManifest";import{DEFAULT_BREAK_WARNINGS as d,DEFAULT_PDT_GRACE_SECONDS as h}from"../types/OptiViewAdsConfig";import{PTS_MATCH_TOLERANCE_SECONDS as l}from"./MetadataCueTracker";import{debugLog as o}from"../diagnostics/debugLog";import{createBreakTimingState as k,describeBreakStart as c,diagnoseAnvatoBreakEnd as u,getBreakStartTime as b,getCurrentTime as g,secondsUntilBreak as S}from"./breakTiming";import{BreakPreloadLedger as m}from"./BreakPreloadLedger";import{skipBreaksStartedBy as p,soonestBreak as B}from"./ssbStream";import{RewindRearm as E}from"./RewindRearm";import{BreakChain as f}from"./BreakChain";import{BreakState as D,systemClock as I}from"./BreakSchedulerTypes";export{BreakState,systemClock}from"./BreakSchedulerTypes";export const TICK_INTERVAL_MS=250;export class BreakScheduler{constructor(e,t=!1,a={enabled:!1,maxGapSeconds:0},i=I,r={enabled:!1,minBreakDurationSeconds:0},s=null,n=d,l=null,o=h){this.breaks=new Map,this.timing=k(),this.checkInterval=null,this.startDeadline=null,this.nextStartDeadlineMs=null,this.onBreakStart=null,this.onBreakApproaching=null,this.onBreakWarning=null,this.onBreakAborted=null,this.onBreakSkipped=null,this.beforeBreakCheck=null,this.breakStartsHeld=!1,this.preloadLedger=new m,this.onAdStartDelayElapsed=null,this.adStartDelayElapsedNotified=!1,this.abortNotifiedBreakIds=new Set,this.breakWarnings=d,this.breakWarningFired=new Map,this.completedBreakIds=new Set,this.unsupportedEventBreakIds=new Set,this.playbackEndedAtMs=null,this.anvatoEnteredDiagnosed=new Set,this.retiredBreaks=new Map,this.minSeenTime=null,this.JOIN_DISCRIMINATOR_SLACK_MS=1e3,this.WINDOW_ESCAPE_GRACE_MS=12e3,this.TIMING_TOLERANCE_MS=5e3,this.PRELOAD_AHEAD_SECONDS=8,this.contentReloading=!1,this.startupSeeking=!1,this.player=e,this.debug=t,this.chain=new f({breaks:this.breaks,enabled:a.enabled,maxGapMs:1e3*Math.max(0,a.maxGapSeconds),toleranceMs:this.TIMING_TOLERANCE_MS,getBreakStartTime:e=>this.getBreakStartTime(e),log:(...e)=>this.log(...e)}),this.tuneInEnabled=r.enabled,this.minBreakDurationMs=1e3*Math.max(0,r.minBreakDurationSeconds),this.clock=i,this.diagnose=s,this.breakWarnings=n,this.cueTracker=l;const c=Math.max(0,o);this.timingDeps={player:this.player,clock:this.clock,cueTracker:this.cueTracker,diagnose:this.diagnose,log:(...e)=>this.log(...e),pdtGraceSeconds:c,pdtGraceMs:1e3*c},this.rewind=new E({breaks:this.breaks,retiredBreaks:this.retiredBreaks,completedBreakIds:this.completedBreakIds,preloadLedger:this.preloadLedger,timing:this.timing,clock:this.clock,log:(...e)=>this.log(...e),getBreakStartTime:e=>this.getBreakStartTime(e)})}claimChain(e){this.chain.claim(e)}getChainedSuccessor(e){return this.chain.successorOf(e)}activateChainedBreak(e){this.chain.activate(e)}setOnChainSuccessorChanged(e){this.chain.setOnSuccessorChanged(e)}updateManifest(e){this.timing.timebase=e.timebase;const t=this.rewind.adStartDelayMs;this.rewind.setAdStartDelayMs(1e3*Math.max(0,e.adStartDelay??0)),t>0&&0===this.rewind.adStartDelayMs&&this.notifyAdStartDelayElapsed();for(const t of e.breaks){if(n(t))continue;if(!this.isSchedulableEvent(t))continue;if(this.completedBreakIds.has(t.id))continue;const e=this.breaks.get(t.id);e?e.state!==D.PENDING&&e.state!==D.CHAINED||(e.break=t):(this.breaks.set(t.id,{break:t,state:D.PENDING}),this.log(`📅 Break scheduled: "${t.id}" at ${c(t)}`))}const a=new Set(e.breaks.map(e=>e.id));for(const[e,t]of this.breaks)a.has(e)||t.state!==D.ACTIVE||this.abortNotifiedBreakIds.has(e)||(this.abortNotifiedBreakIds.add(e),this.log("Break removed from manifest while active (early return):",e),this.diagnose?.("DA-BREAK-EARLY-RETURN","Active break removed from manifest; returning to content early",{breakId:e}),this.onBreakAborted?.(t.break));this.cleanupBreaks(a);const i=this.getActiveBreak();i&&!this.abortNotifiedBreakIds.has(i.id)&&this.chain.refresh(i)}applyEventBoundary(e){const t=this.rewind.playbackStarted;this.updateManifest(t?{...e,adStartDelay:0}:e),t&&this.rewind.ignoreAdStartDelay()}setEventBoundaryCheck(e){this.beforeBreakCheck=e}resetForChannelSwitch(e){const t=this.getActiveBreak();for(const e of[...this.breaks.keys()])e!==t?.id&&this.breaks.delete(e);for(const e of[...this.abortNotifiedBreakIds])e!==t?.id&&this.abortNotifiedBreakIds.delete(e);this.completedBreakIds.clear(),this.retiredBreaks.clear(),this.preloadLedger.clear(),this.breakWarningFired.clear(),this.unsupportedEventBreakIds.clear(),this.anvatoEnteredDiagnosed.clear(),this.timing.anvatoPendingDiagnosed.clear(),this.timing.anvatoMatchedDiagnosed.clear(),this.timing.anvatoEndDiagnosed.clear(),this.playbackEndedAtMs=null,this.rewind.beginChannel();const a=t?{...e,breaks:e.breaks.filter(e=>e.id!==t.id)}:e;this.updateManifest(a)}isSchedulableEvent(t){return!s(t.start)||t.start.event===e.START||t.start.event===e.END||(this.unsupportedEventBreakIds.has(t.id)||(this.unsupportedEventBreakIds.add(t.id),this.log(`⚠️ Break ignored: "${t.id}" (unsupported event trigger "${t.start.event}")`),this.diagnose?.("DA-BREAK-EVENT-UNSUPPORTED","Break triggered by an event this SDK version does not schedule; the break was ignored",{breakId:t.id,event:t.start.event})),!1)}markPlaybackStart(){null!==this.playbackEndedAtMs&&(this.playbackEndedAtMs=null,this.log("Content replayed; pending post-rolls cancelled")),this.rewind.playbackStarted||(this.rewind.markPlaybackStart(this.peekPosition()),this.log("Content playback started at",new Date(this.clock.now()).toISOString()))}setOnAdStartDelayElapsed(e){this.onAdStartDelayElapsed=e}holdBreakStarts(){this.breakStartsHeld=!0}releaseBreakStarts(){const e=this.breakStartsHeld;this.breakStartsHeld=!1,this.preloadLedger.checkAtBreakStart(e,()=>this.checkBreaks())}areBreakStartsHeld(){return this.breakStartsHeld||this.rewind.isAdStartDelayActive()}notifyAdStartDelayElapsed(){this.adStartDelayElapsedNotified||(this.adStartDelayElapsedNotified=!0,this.onAdStartDelayElapsed?.())}markPlaybackEnd(){null===this.playbackEndedAtMs&&(this.playbackEndedAtMs=this.clock.now(),this.log("Content playback ended at",new Date(this.playbackEndedAtMs).toISOString()))}start(e,t,a,i,r){this.onBreakStart=e,this.onBreakApproaching=t??null,this.onBreakWarning=a??null,this.onBreakAborted=i??null,this.onBreakSkipped=r??null,this.checkInterval&&clearInterval(this.checkInterval),this.checkInterval=setInterval(()=>{this.tick()},250),this.log("Scheduler started")}tick(){!1!==this.beforeBreakCheck?.(this.getCurrentTime())&&(this.checkBreaks(),null!==this.nextStartDeadlineMs&&this.armStartDeadline(this.nextStartDeadlineMs))}armStartDeadline(e){null!==this.checkInterval&&null===this.startDeadline&&(this.startDeadline=setTimeout(()=>{this.startDeadline=null,this.tick()},Math.max(1,Math.ceil(e))))}clearStartDeadline(){this.startDeadline&&clearTimeout(this.startDeadline),this.startDeadline=null}suspend(){this.checkInterval&&clearInterval(this.checkInterval),this.checkInterval=null,this.clearStartDeadline()}resume(){!this.checkInterval&&this.onBreakStart&&(this.checkInterval=setInterval(()=>this.tick(),250))}skipPendingBreaksDueBy(e){return p(this.getCurrentTime(),[...this.breaks.values()],e=>e.state===D.PENDING?this.getBreakStartTime(e.break):null,t=>this.skipBreak(t,e))}stop(){this.checkInterval&&(clearInterval(this.checkInterval),this.checkInterval=null),this.clearStartDeadline(),this.onBreakStart=null,this.onBreakSkipped=null,this.log("Scheduler stopped")}completeBreak(e){this.completedBreakIds.add(e),this.breakWarningFired.delete(e),this.abortNotifiedBreakIds.delete(e);const t=this.breaks.get(e);t&&(this.log("Break completed and removed:",e),null===a(t.break)&&null===this.cueTracker&&this.retiredBreaks.set(e,t.break),this.breaks.delete(e),this.preloadLedger.delete(e))}setContentReloading(e){this.contentReloading=e,this.rewind.setContentReloading(e||this.startupSeeking)}setStartupSeeking(e){this.startupSeeking=e,this.rewind.setContentReloading(e||this.contentReloading)}notifyResumeSeek(e,t){this.rewind.notifyResumeSeek(e,t)}notifyViewerSeek(){this.rewind.notifyViewerSeek()}skipBreak(e,t){e.state=D.SKIPPED,this.completedBreakIds.add(e.break.id),this.onBreakSkipped?.(e.break,t)}cleanupBreaks(e){const t=[];for(const[a,i]of this.breaks)i.state!==D.COMPLETED&&i.state!==D.SKIPPED?e.has(a)||i.state===D.ACTIVE||(this.skipBreak(i,"removed"),t.push(a)):t.push(a);for(const e of t)this.breaks.delete(e),this.preloadLedger.delete(e),this.breakWarningFired.delete(e)}getActiveBreak(){for(const e of this.breaks.values())if(e.state===D.ACTIVE)return e.break;return null}getSecondsUntilBreak(e){const t=this.breaks.get(e);if(!t||t.state!==D.PENDING)return null;const a=this.getCurrentTime();if(null===a)return null;const i=this.getBreakStartTime(t.break);return null===i?null:S(i,a)}getNextPendingBreak(){return B([...this.breaks.keys()],e=>this.getSecondsUntilBreak(e))}notifyCuePresented(e){if(null===this.cueTracker||this.timing.timebase!==t.PTS)return null;if(!Number.isFinite(e))return null;let a=null;for(const t of this.breaks.values())if(t.state===D.PENDING&&"number"==typeof t.break.start&&!(Math.abs(t.break.start-e)>l)){a=t.break.id;break}if(null===a)return null;const i=this.player.currentTime;this.checkBreaks();const r=this.breaks.get(a);return r&&r.state===D.ACTIVE?this.anvatoEnteredDiagnosed.has(a)?null:(this.anvatoEnteredDiagnosed.add(a),this.log(`🎯 Break "${a}" armed by cue presentation (pts ${e})`),this.diagnose?.("DA-ANVATO-CUE-ENTERED",`Break "${a}" started from the presented cue (pts ${e}) rather than the scheduler tick.`,{breakId:a,pts:e,mediaTimeSec:i}),a):null}checkBreaks(){if(this.nextStartDeadlineMs=null,this.startupSeeking)return;const e=this.getCurrentTime();this.rewind.trackPlayedTime(e),this.rewind.adStartDelayMs>0&&!this.rewind.isAdStartDelayActive()&&this.notifyAdStartDelayElapsed();const a=this.areBreakStartsHeld();null!==e&&(this.minSeenTime=null===this.minSeenTime?e:Math.min(this.minSeenTime,e),this.rewind.rearmOnRewind(e));for(const s of this.breaks.values()){if(s.state===D.ACTIVE&&this.timing.timebase===t.WALLCLOCK&&null!==e&&!this.abortNotifiedBreakIds.has(s.break.id)){const t=this.getBreakStartTime(s.break),a=1e3*(s.break.duration??0);null!==t&&a>0&&e>t+a+this.WINDOW_ESCAPE_GRACE_MS&&(this.abortNotifiedBreakIds.add(s.break.id),this.log(`⚠️ Break window escaped: "${s.break.id}" (ended ${Math.round((e-t-a)/1e3)}s ago on the stream clock)`),this.diagnose?.("DA-BREAK-WINDOW-ESCAPED","Active break outlived its wallclock window; returning to content",{breakId:s.break.id,overrunSec:Math.round((e-t-a)/100)/10}),this.onBreakAborted?.(s.break));continue}if(s.state===D.ACTIVE&&this.timing.timebase===t.PTS&&u(this.timing,this.timingDeps,s.break),s.state!==D.PENDING)continue;const n=r(s.break);if(null!==n){this.checkPreRollBreak(s,n,a);continue}const d=i(s.break);if(null!==d){this.checkPostRollBreak(s,d,a);continue}if(null===e)continue;if(a)continue;null!==this.cueTracker&&this.timing.timebase===t.PTS&&this.maybePreload(s.break,"manifest arrival — Anvato flow");const h=this.getBreakStartTime(s.break);if(null===h)continue;const l=e-h,o=Math.round(-l/1e3);if(this.timing.timebase===t.WALLCLOCK&&l<0&&-l<=250&&(this.nextStartDeadlineMs=Math.min(this.nextStartDeadlineMs??1/0,-l)),this.checkWarnings(s.break,o),o>0&&o<=15&&o%2==0&&this.log(`⏱️ Break "${s.break.id}" starts in ${o}s`),o>0&&o<=this.PRELOAD_AHEAD_SECONDS&&this.maybePreload(s.break,`${o}s ahead`),l>=0&&l<=this.TIMING_TOLERANCE_MS){const e=Math.max(0,l),t=1e3*(s.break.duration??0)-e;if(t<=0){this.log(`⚠️ Break missed: "${s.break.id}" (ended ${Math.round(-t/1e3)}s ago, inside the start tolerance)`),this.skipBreak(s,t>0&&this.tuneInEnabled?"insufficient-remaining":"late"),null===this.cueTracker&&this.breaks.get(s.break.id)===s&&this.retiredBreaks.set(s.break.id,s.break);break}if(null!==this.minSeenTime&&h<this.minSeenTime-this.JOIN_DISCRIMINATOR_SLACK_MS&&(!this.tuneInEnabled||t<this.minBreakDurationMs)){this.log(`⚠️ Break missed: "${s.break.id}" (joined in progress inside the start tolerance, ${Math.round(t/1e3)}s remaining < tune-in rules)`),this.skipBreak(s,t>0&&this.tuneInEnabled?"insufficient-remaining":"late"),null===this.cueTracker&&this.breaks.get(s.break.id)===s&&this.retiredBreaks.set(s.break.id,s.break);break}this.preloadLedger.shouldRetryRejectedAtStart(s.break.id)&&this.maybePreload(s.break,"retrying a rejected preload at break start"),this.log(`🎬 BREAK TRIGGERED: "${s.break.id}"`),s.state=D.ACTIVE,this.onBreakStart&&this.onBreakStart(s.break,{tuneIn:!1,elapsedSec:e/1e3,remainingSec:t/1e3});break}if(l>this.TIMING_TOLERANCE_MS){const t=h+1e3*(s.break.duration??0)-e;if(this.tuneInEnabled&&t>=this.minBreakDurationMs&&t>0){this.log(`🎬 TUNE-IN BREAK TRIGGERED: "${s.break.id}" (${Math.round(t/1e3)}s remaining)`),s.state=D.ACTIVE,this.onBreakStart&&this.onBreakStart(s.break,{tuneIn:!0,elapsedSec:l/1e3,remainingSec:t/1e3});break}this.log(`⚠️ Break missed: "${s.break.id}" (was ${Math.round(l/1e3)}s ago)`),this.skipBreak(s,t>0&&this.tuneInEnabled?"insufficient-remaining":"late"),null===this.cueTracker&&this.breaks.get(s.break.id)===s&&this.retiredBreaks.set(s.break.id,s.break)}}}checkPreRollBreak(e,t,a){if(!this.rewind.playbackStarted)return;const i=1e3*t;if(this.rewind.adStartDelayMs>0&&i<this.rewind.adStartDelayMs)return this.log(`⚠️ Pre-roll skipped: "${e.break.id}" (delay ${t}s < adStartDelay ${this.rewind.adStartDelayMs/1e3}s)`),void this.skipBreak(e,"start-delay");const r=this.rewind.channelPlayedMs,s=Math.round((i-r)/1e3);s>0&&s<=15&&s%2==0&&this.log(`⏱️ Pre-roll "${e.break.id}" starts in ${s}s`),s>0&&s<=this.PRELOAD_AHEAD_SECONDS&&this.maybePreload(e.break,`pre-roll, ${s}s ahead`),r>=i&&!a&&(this.log(`🎬 PRE-ROLL TRIGGERED: "${e.break.id}"${t>0?` (after ${t}s delay)`:""}`),e.state=D.ACTIVE,this.onBreakStart&&this.onBreakStart(e.break,{tuneIn:!1,elapsedSec:0,remainingSec:e.break.duration??0}))}checkPostRollBreak(e,t,a){if(null===this.playbackEndedAtMs)return;const i=1e3*t,r=this.clock.now()-this.playbackEndedAtMs,s=Math.round((i-r)/1e3);s>0&&s<=this.PRELOAD_AHEAD_SECONDS&&this.maybePreload(e.break,`post-roll, ${s}s ahead`),r>=i&&!a&&(this.log(`🎬 POST-ROLL TRIGGERED: "${e.break.id}"${t>0?` (after ${t}s delay)`:""}`),e.state=D.ACTIVE,this.onBreakStart&&this.onBreakStart(e.break,{tuneIn:!1,elapsedSec:0,remainingSec:e.break.duration??0}))}isAdStartDelayActive(){return this.areBreakStartsHeld()}getCurrentTime(){return g(this.timing,this.timingDeps)}maybePreload(e,t){if(this.preloadLedger.wasPreloaded(e.id)||!this.onBreakApproaching)return;this.log(`⏳ Preloading break "${e.id}" (${t})`);const a=!1!==this.onBreakApproaching(e);this.preloadLedger.recordAttempt(e.id,a)}getBreakStartTime(e){return s(e.start)?null:b(this.timing,this.timingDeps,e)}peekPosition(){if(this.timing.timebase!==t.WALLCLOCK)return 1e3*this.player.currentTime;const e=this.player.programDateTime?.getTime();return void 0===e||isNaN(e)?null:e}destroy(){this.stop(),this.breaks.clear(),this.preloadLedger.clear(),this.completedBreakIds.clear(),this.retiredBreaks.clear(),this.minSeenTime=null,this.breakStartsHeld=!1,this.onAdStartDelayElapsed=null,this.adStartDelayElapsedNotified=!1,this.unsupportedEventBreakIds.clear(),this.playbackEndedAtMs=null,this.rewind.reset(),this.breakWarningFired.clear(),this.abortNotifiedBreakIds.clear(),this.timing.pdtMissingWarned=!1,this.timing.pdtSeen=!1,this.timing.firstPdtAttemptMs=null,this.timing.playbackStartedAtMs=null,this.timing.anvatoPendingDiagnosed.clear(),this.timing.anvatoMatchedDiagnosed.clear(),this.timing.anvatoEndDiagnosed.clear(),this.cueTracker?.clear()}checkWarnings(e,t){if(t<=0||0===this.breakWarnings.seconds.length)return;let a=this.breakWarningFired.get(e.id);a||(a=new Set,this.breakWarningFired.set(e.id,a));for(const i of this.breakWarnings.seconds)a.has(i)||t<=i&&(a.add(i),this.log(`Break warning for "${e.id}" (${t}s <= ${i}s)`),this.onBreakWarning?.(e,i,t))}log(...e){this.debug&&o("[OptiViewAds:BreakScheduler]",...e)}}
|