@dolby-optiview/ads-sdk-core 1.0.0-beta.6 → 1.1.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.
Files changed (113) hide show
  1. package/README.md +68 -0
  2. package/dist/OptiViewAds.d.ts +1 -0
  3. package/dist/OptiViewAds.js +1 -1
  4. package/dist/diagnostics/DiagnosticEvent.d.ts +2 -0
  5. package/dist/diagnostics/playbackErrorContext.d.ts +0 -17
  6. package/dist/diagnostics/playbackErrorContext.js +1 -1
  7. package/dist/diagnostics/recordEventTimeline.d.ts +3 -0
  8. package/dist/diagnostics/recordEventTimeline.js +1 -0
  9. package/dist/generated/diagnosticCodes.d.ts +111 -1
  10. package/dist/generated/diagnosticCodes.js +1 -1
  11. package/dist/generated/version.d.ts +1 -1
  12. package/dist/generated/version.js +1 -1
  13. package/dist/id3/parseId3Geob.d.ts +26 -5
  14. package/dist/index.d.ts +4 -2
  15. package/dist/index.js +1 -1
  16. package/dist/interfaces/PlayerAdapter.d.ts +45 -1
  17. package/dist/internal/index.d.ts +1 -1
  18. package/dist/internal/index.js +1 -1
  19. package/dist/server/index.d.ts +3 -1
  20. package/dist/server/index.js +1 -1
  21. package/dist/services/AdPlayerController.d.ts +11 -9
  22. package/dist/services/AdPlayerController.js +1 -1
  23. package/dist/services/BreakScheduler.d.ts +5 -2
  24. package/dist/services/BreakScheduler.js +1 -1
  25. package/dist/services/CmcdAdReporter.d.ts +33 -3
  26. package/dist/services/CmcdAdReporter.js +1 -1
  27. package/dist/services/GamPodAdTracker.d.ts +15 -2
  28. package/dist/services/GamPodAdTracker.js +1 -1
  29. package/dist/services/GamStreamManager.js +1 -1
  30. package/dist/services/LensReporter.d.ts +3 -1
  31. package/dist/services/LensReporter.js +1 -1
  32. package/dist/services/LiveStartPushbackController.d.ts +36 -0
  33. package/dist/services/LiveStartPushbackController.js +1 -0
  34. package/dist/services/MetadataCueTracker.d.ts +15 -0
  35. package/dist/services/MetadataCueTracker.js +1 -1
  36. package/dist/services/SsaiController.js +1 -1
  37. package/dist/services/StitcherUrlBuilder.js +1 -1
  38. package/dist/services/VastAdManager.js +1 -1
  39. package/dist/services/adPlayer/AdPlayerEvents.js +1 -1
  40. package/dist/services/adPlayer/AdPlayerState.d.ts +14 -0
  41. package/dist/services/adPlayer/AdPlayerState.js +1 -1
  42. package/dist/services/adPlayer/AdPreloader.d.ts +9 -1
  43. package/dist/services/adPlayer/AdPreloader.js +1 -1
  44. package/dist/services/adPlayer/AdStage.d.ts +6 -0
  45. package/dist/services/adPlayer/AdStage.js +1 -1
  46. package/dist/services/adPlayer/AssetParameterResolver.js +1 -1
  47. package/dist/services/adPlayer/AssetPlayback.d.ts +15 -1
  48. package/dist/services/adPlayer/AssetPlayback.js +1 -1
  49. package/dist/services/adPlayer/ContentRecovery.d.ts +32 -0
  50. package/dist/services/adPlayer/ContentRecovery.js +1 -0
  51. package/dist/services/adPlayer/ContentResumeCoordinator.d.ts +46 -0
  52. package/dist/services/adPlayer/ContentResumeCoordinator.js +1 -1
  53. package/dist/services/adPlayer/GamPodBridge.d.ts +7 -0
  54. package/dist/services/adPlayer/GamPodBridge.js +1 -1
  55. package/dist/services/adPlayer/PlaybackCutoff.d.ts +3 -0
  56. package/dist/services/adPlayer/PlaybackCutoff.js +1 -0
  57. package/dist/services/adPlayer/PreparedPresentation.d.ts +32 -0
  58. package/dist/services/adPlayer/PreparedPresentation.js +1 -0
  59. package/dist/services/adPlayer/SharedElementBreakPlayer.d.ts +15 -1
  60. package/dist/services/adPlayer/SharedElementBreakPlayer.js +1 -1
  61. package/dist/services/adPlayer/classifyMediaError.d.ts +9 -0
  62. package/dist/services/adPlayer/classifyMediaError.js +1 -0
  63. package/dist/services/adPlayer/liveEdge.d.ts +29 -0
  64. package/dist/services/adPlayer/liveEdge.js +1 -1
  65. package/dist/services/anvatoCueRuntime.d.ts +7 -0
  66. package/dist/services/anvatoCueRuntime.js +1 -1
  67. package/dist/services/classifyImaAdError.d.ts +6 -0
  68. package/dist/services/classifyImaAdError.js +1 -0
  69. package/dist/services/detectContentRecovery.d.ts +12 -0
  70. package/dist/services/detectContentRecovery.js +1 -0
  71. package/dist/services/detectInsertionMode.js +1 -1
  72. package/dist/services/fetchWithTimeout.js +1 -1
  73. package/dist/services/html5ImaErrorNames.d.ts +2 -0
  74. package/dist/services/html5ImaErrorNames.js +1 -0
  75. package/dist/services/lensBackend.d.ts +1 -1
  76. package/dist/services/resolveGamVendorConfiguration.js +1 -1
  77. package/dist/services/resolveLiveStartPushback.d.ts +1 -0
  78. package/dist/services/resolveLiveStartPushback.js +1 -0
  79. package/dist/services/resolvedModeDiagnostics.d.ts +18 -0
  80. package/dist/services/resolvedModeDiagnostics.js +1 -0
  81. package/dist/services/runtimeObject.d.ts +2 -0
  82. package/dist/services/runtimeObject.js +1 -0
  83. package/dist/services/webCompatibility.d.ts +4 -0
  84. package/dist/services/webCompatibility.js +1 -0
  85. package/dist/services/webRuntime.d.ts +8 -0
  86. package/dist/services/webRuntime.js +1 -0
  87. package/dist/services/xhrWithTimeout.d.ts +1 -0
  88. package/dist/services/xhrWithTimeout.js +1 -0
  89. package/dist/session/AdBreakStatusTracker.d.ts +6 -3
  90. package/dist/session/AdBreakStatusTracker.js +1 -1
  91. package/dist/session/BreakLifecycle.js +1 -1
  92. package/dist/session/SessionStarter.d.ts +1 -0
  93. package/dist/session/SessionStarter.js +1 -1
  94. package/dist/types/AdError.d.ts +12 -0
  95. package/dist/types/AdError.js +1 -0
  96. package/dist/types/Events.d.ts +1 -1
  97. package/dist/types/OptiViewAdsConfig.d.ts +42 -5
  98. package/dist/types/OptiViewAdsConfig.js +1 -1
  99. package/dist/types/VendorAdError.d.ts +6 -5
  100. package/dist/types/VendorAdError.js +1 -1
  101. package/dist/types/compatibility-modules.d.ts +4 -0
  102. package/dist/types/compatibility-modules.js +1 -0
  103. package/dist/vendor/lens-sdk/THIRD-PARTY-NOTICES.txt +1 -1
  104. package/dist/vendor/lens-sdk/index.d.ts +1 -1
  105. package/dist/vendor/lens-sdk/index.js +1 -1
  106. package/dist/vendor/lens-sdk/lens-core-uGZfZpQy.js +1 -0
  107. package/dist/vendor/lens-sdk/lens.d.ts +2 -0
  108. package/dist/vendor/lens-sdk/teardown.d.ts +13 -0
  109. package/dist/vendor/lens-sdk/transport.d.ts +11 -2
  110. package/dist/vendor/lens-sdk/types.d.ts +56 -5
  111. package/dist/vendor/lens-sdk/validation.d.ts +4 -1
  112. package/package.json +6 -2
  113. package/dist/vendor/lens-sdk/lens-core-Q5lbQGMC.js +0 -1
@@ -6,7 +6,11 @@
6
6
  * and passes the body through undecoded). Lives in core because both adapters consume it and an
7
7
  * adapter must never depend on another adapter; exposed as `@dolby-optiview/ads-sdk-core/id3`.
8
8
  */
9
- /** A single parsed ID3v2 GEOB frame. */
9
+ /**
10
+ * A single parsed ID3v2 GEOB frame.
11
+ *
12
+ * @category Player Integration
13
+ */
10
14
  export interface Id3GeobFrame {
11
15
  /** GEOB MIME type (always latin1 in the tag), e.g. `application/json`. */
12
16
  mimeType: string;
@@ -17,12 +21,29 @@ export interface Id3GeobFrame {
17
21
  /** The encapsulated object bytes (undecoded). */
18
22
  data: Uint8Array;
19
23
  }
20
- /** Empty array for anything that is not a well-formed ID3v2.3/2.4 tag; never throws. */
24
+ /**
25
+ * Parse the GEOB frames of an ID3v2 tag, as carried in HLS timed metadata.
26
+ *
27
+ * @param bytes The complete ID3v2 tag.
28
+ * @returns The GEOB frames in order; an empty array for anything that is not a well-formed
29
+ * ID3v2.3/2.4 tag. Never throws.
30
+ * @category Player Integration
31
+ */
21
32
  export declare function parseId3GeobFrames(bytes: Uint8Array): Id3GeobFrame[];
22
33
  /**
23
- * GEOB frame body (after the 10-byte frame header): encoding byte, MIME (latin1, NUL), file name
24
- * (NUL, frame encoding), description (NUL, frame encoding), object data. Null when malformed; never throws.
34
+ * Parse one GEOB frame body (after the 10-byte frame header): encoding byte, MIME (latin1, NUL),
35
+ * file name (NUL, frame encoding), description (NUL, frame encoding), object data.
36
+ *
37
+ * @param body The frame body bytes.
38
+ * @returns The parsed frame, or null when malformed. Never throws.
39
+ * @category Player Integration
25
40
  */
26
41
  export declare function parseId3GeobBody(body: Uint8Array): Id3GeobFrame | null;
27
- /** Decode UTF-8 bytes (also used for the GEOB object data / Anvato payload). */
42
+ /**
43
+ * Decode UTF-8 bytes, e.g. the object data of a GEOB frame.
44
+ *
45
+ * @param bytes The encoded text.
46
+ * @returns The decoded string.
47
+ * @category Player Integration
48
+ */
28
49
  export declare function decodeUtf8(bytes: Uint8Array): string;
package/dist/index.d.ts CHANGED
@@ -6,8 +6,8 @@ export { isStaticAsset, isVastAsset, isVendorAsset, isGamVendorConfiguration, is
6
6
  export { resolveDeliveryMode, resolveStitchedStreamVendor, SsaiUnavailableError, } from './services/resolveDeliveryMode';
7
7
  export type { DeliveryModeDecision } from './services/resolveDeliveryMode';
8
8
  export type { StitchedStreamVendor } from './services/resolveDeliveryMode';
9
- export type { OptiViewAdsConfig, OptiViewAdsMode, PtsSource, GamConfig, SessionConfig, SsaiSessionConfig, StartSessionConfig, CreateAdAdapter, AdPreloadMode, AdInsertionMode, AdInsertionType, SsaiConfig, DoubleBoxAudio, ChainingConfig, ResolvedChaining, TuneInConfig, ResolvedTuneIn, ManifestResponseInterceptor, ManifestInterceptContext, ManifestRequestInterceptor, ManifestRequestContext, ManifestRequest, ManifestMockResponse, ManifestRequestInterceptorResult, } from './types/OptiViewAdsConfig';
10
- export { DEFAULT_MODE, DEFAULT_AD_PRELOAD_MODE, DEFAULT_AD_INSERTION_MODE, DEFAULT_CHAINING, resolveChaining, DEFAULT_TUNE_IN, resolveTuneIn, DEFAULT_PDT_GRACE_SECONDS, resolvePdtGraceSeconds, } from './types/OptiViewAdsConfig';
9
+ export type { OptiViewAdsConfig, LiveStartPushbackConfig, OptiViewAdsMode, PtsSource, GamConfig, SessionConfig, SsaiSessionConfig, StartSessionConfig, CreateAdAdapter, AdPreloadMode, AdBreakContentRecovery, AdInsertionMode, AdInsertionType, SsaiConfig, DoubleBoxAudio, ChainingConfig, ResolvedChaining, TuneInConfig, ResolvedTuneIn, ManifestResponseInterceptor, ManifestInterceptContext, ManifestRequestInterceptor, ManifestRequestContext, ManifestRequest, ManifestMockResponse, ManifestRequestInterceptorResult, } from './types/OptiViewAdsConfig';
10
+ export { DEFAULT_MODE, DEFAULT_AD_PRELOAD_MODE, DEFAULT_AD_BREAK_CONTENT_RECOVERY, DEFAULT_AD_INSERTION_MODE, DEFAULT_CHAINING, resolveChaining, DEFAULT_TUNE_IN, resolveTuneIn, DEFAULT_PDT_GRACE_SECONDS, resolvePdtGraceSeconds, } from './types/OptiViewAdsConfig';
11
11
  export type { StitcherMasterUrlParams } from './services/StitcherUrlBuilder';
12
12
  export { buildStitcherMasterUrl } from './services/StitcherUrlBuilder';
13
13
  export type { GamStreamConfig, GamAdEventCallbacks } from './services/GamStreamManager';
@@ -21,6 +21,8 @@ export type { SsaiControllerOptions, SsaiControllerCallbacks } from './services/
21
21
  export { SsaiController } from './services/SsaiController';
22
22
  export type { ResolvedPreloadMode } from './services/detectPreloadMode';
23
23
  export { resolvePreloadMode, isSingleDecoderUserAgent } from './services/detectPreloadMode';
24
+ export type { ResolvedContentRecovery } from './services/detectContentRecovery';
25
+ export { resolveContentRecovery, isRecreateAfterBreakUserAgent, } from './services/detectContentRecovery';
24
26
  export type { ResolvedInsertionMode, MediaSourceCapabilities, } from './services/detectInsertionMode';
25
27
  export { resolveInsertionMode, isSharedElementUserAgent, detectMediaSourceCapabilities, } from './services/detectInsertionMode';
26
28
  export type { Clock, TuneInOptions, BreakStartContext } from './services/BreakScheduler';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export{OptiViewAds}from"./OptiViewAds";export{BreakFormat,AssetType,MediaType,Vendor,Timebase,DeviceType,DeliveryMode,BreakEvent}from"./types/BreakManifest";export{isStaticAsset,isVastAsset,isVendorAsset,isGamVendorConfiguration,isEventTrigger,isPauseBreak}from"./types/BreakManifest";export{resolveDeliveryMode,resolveStitchedStreamVendor,SsaiUnavailableError}from"./services/resolveDeliveryMode";export{DEFAULT_MODE,DEFAULT_AD_PRELOAD_MODE,DEFAULT_AD_INSERTION_MODE,DEFAULT_CHAINING,resolveChaining,DEFAULT_TUNE_IN,resolveTuneIn,DEFAULT_PDT_GRACE_SECONDS,resolvePdtGraceSeconds}from"./types/OptiViewAdsConfig";export{buildStitcherMasterUrl}from"./services/StitcherUrlBuilder";export{GamStreamManager}from"./services/GamStreamManager";export{OPTIVIEW_ASSET_PARAMETER_MACROS}from"./services/assetParameterMacros";export{VastAdManager,isImaCsaiSdkAvailable}from"./services/VastAdManager";export{SsaiController}from"./services/SsaiController";export{resolvePreloadMode,isSingleDecoderUserAgent}from"./services/detectPreloadMode";export{resolveInsertionMode,isSharedElementUserAgent,detectMediaSourceCapabilities}from"./services/detectInsertionMode";export{systemClock}from"./services/BreakScheduler";export{MetadataCueTracker,isAnvatoCue,isId3InEmsgScheme,anvatoPayloadFromCue,parseAnvatoPayload,ANVATO_ID3_DESCRIPTION,ANVATO_ID3_MIME_TYPE,ANVATO_EMSG_SCHEME_ID_URI,ID3_IN_EMSG_SCHEME_ID_URIS,PTS_MATCH_TOLERANCE_SECONDS}from"./services/MetadataCueTracker";export{PauseAdController}from"./services/PauseAdController";export{parseVastCompanionImage}from"./services/parseVastCompanion";export{AdBreakSequencer,selectVariant,extractAssets,assetsOfVariant,resolveBreakFormat,breakPlanEmptyReason}from"./services/AdBreakSequencer";export{selectVariantDetailed,playableFormatsFor,variantsOf,RENDERABLE_BREAK_FORMATS,KNOWN_BREAK_FORMATS}from"./services/selectVariant";export{GamPodAdTracker,derivePodAdAsset}from"./services/GamPodAdTracker";export{DIAGNOSTIC_CODES,getDiagnosticCodeInfo,DiagnosticBuffer,DEFAULT_DIAGNOSTIC_BUFFER_SIZE,SDK_VERSION}from"./diagnostics";export{parseBreakManifest,SUPPORTED_MANIFEST_MAJOR_VERSION}from"./services/parseBreakManifest";export{fetchWithTimeout,AUX_FETCH_TIMEOUT_MS}from"./services/fetchWithTimeout";export{buildGamPodUrl,isGamVendorParameters}from"./services/GamPodUrlBuilder";
1
+ export{OptiViewAds}from"./OptiViewAds";export{BreakFormat,AssetType,MediaType,Vendor,Timebase,DeviceType,DeliveryMode,BreakEvent}from"./types/BreakManifest";export{isStaticAsset,isVastAsset,isVendorAsset,isGamVendorConfiguration,isEventTrigger,isPauseBreak}from"./types/BreakManifest";export{resolveDeliveryMode,resolveStitchedStreamVendor,SsaiUnavailableError}from"./services/resolveDeliveryMode";export{DEFAULT_MODE,DEFAULT_AD_PRELOAD_MODE,DEFAULT_AD_BREAK_CONTENT_RECOVERY,DEFAULT_AD_INSERTION_MODE,DEFAULT_CHAINING,resolveChaining,DEFAULT_TUNE_IN,resolveTuneIn,DEFAULT_PDT_GRACE_SECONDS,resolvePdtGraceSeconds}from"./types/OptiViewAdsConfig";export{buildStitcherMasterUrl}from"./services/StitcherUrlBuilder";export{GamStreamManager}from"./services/GamStreamManager";export{OPTIVIEW_ASSET_PARAMETER_MACROS}from"./services/assetParameterMacros";export{VastAdManager,isImaCsaiSdkAvailable}from"./services/VastAdManager";export{SsaiController}from"./services/SsaiController";export{resolvePreloadMode,isSingleDecoderUserAgent}from"./services/detectPreloadMode";export{resolveContentRecovery,isRecreateAfterBreakUserAgent}from"./services/detectContentRecovery";export{resolveInsertionMode,isSharedElementUserAgent,detectMediaSourceCapabilities}from"./services/detectInsertionMode";export{systemClock}from"./services/BreakScheduler";export{MetadataCueTracker,isAnvatoCue,isId3InEmsgScheme,anvatoPayloadFromCue,parseAnvatoPayload,ANVATO_ID3_DESCRIPTION,ANVATO_ID3_MIME_TYPE,ANVATO_EMSG_SCHEME_ID_URI,ID3_IN_EMSG_SCHEME_ID_URIS,PTS_MATCH_TOLERANCE_SECONDS}from"./services/MetadataCueTracker";export{PauseAdController}from"./services/PauseAdController";export{parseVastCompanionImage}from"./services/parseVastCompanion";export{AdBreakSequencer,selectVariant,extractAssets,assetsOfVariant,resolveBreakFormat,breakPlanEmptyReason}from"./services/AdBreakSequencer";export{selectVariantDetailed,playableFormatsFor,variantsOf,RENDERABLE_BREAK_FORMATS,KNOWN_BREAK_FORMATS}from"./services/selectVariant";export{GamPodAdTracker,derivePodAdAsset}from"./services/GamPodAdTracker";export{DIAGNOSTIC_CODES,getDiagnosticCodeInfo,DiagnosticBuffer,DEFAULT_DIAGNOSTIC_BUFFER_SIZE,SDK_VERSION}from"./diagnostics";export{parseBreakManifest,SUPPORTED_MANIFEST_MAJOR_VERSION}from"./services/parseBreakManifest";export{fetchWithTimeout,AUX_FETCH_TIMEOUT_MS}from"./services/fetchWithTimeout";export{buildGamPodUrl,isGamVendorParameters}from"./services/GamPodUrlBuilder";
@@ -37,6 +37,13 @@ export interface TimedMetadataCue {
37
37
  * parsed cue as `presented` can cause an ad break to start before its scheduled time.
38
38
  */
39
39
  phase?: 'parsed' | 'presented' | undefined;
40
+ /**
41
+ * Player media time minus the stream's PTS clock, in seconds, when the adapter knows it
42
+ * (DASH: `Period@start - presentationTimeOffset / timescale`). A DASH emsg whose
43
+ * `presentation_time_delta` is 0 reports its carrying segment's start as `startTime`; with
44
+ * this offset the core places an in-band break cue at its own `pts` instead.
45
+ */
46
+ ptsOffset?: number | undefined;
40
47
  }
41
48
  /** For `timedmetadata` the payload is a {@link TimedMetadataCue}; other events are event-specific (often undefined, or a media error for `error`). @category Player Integration */
42
49
  export type PlayerAdapterEventHandler = (event?: unknown) => void;
@@ -93,8 +100,19 @@ export interface PlayerAdapter {
93
100
  * Release the held media without destroying the adapter; the next `load()` must reattach it.
94
101
  * Called on single-decoder TVs at break end, before content resumes, to free the hardware
95
102
  * decoder and avoid `MEDIA_ERR_DECODE`. Not called in parallel-preload mode.
103
+ * When it returns a promise, the SDK awaits it before resuming content.
96
104
  */
97
- unload?(): void;
105
+ unload?(): void | Promise<void>;
106
+ /**
107
+ * Optional: tear down and rebuild the engine's media pipeline (MediaSource / source buffers) for
108
+ * the CURRENT source, positioned at `startTime` seconds. Called at break end on TVs that cannot
109
+ * resume content in the MediaSource an ad interrupted (VIZIO SmartCast). Resolve once metadata
110
+ * for the rebuilt pipeline is available; reject on failure — the SDK then falls back to seek+play.
111
+ * Must not destroy the adapter. Omit when the engine has no such operation.
112
+ */
113
+ recreateMediaPipeline?(options: {
114
+ startTime: number;
115
+ }): Promise<void>;
98
116
  /**
99
117
  * Optional capability hint: can content and ad pipelines buffer in parallel without decoder
100
118
  * contention? `false` prevents continued content playout during a break. Undefined counts as capable.
@@ -135,6 +153,27 @@ export interface PlayerAdapter {
135
153
  * and rejects sentinel values.
136
154
  */
137
155
  readonly seekableEnd?: number | null;
156
+ /** Start of the same seekable range as seekableEnd; null/omitted when unknown. */
157
+ readonly seekableStart?: number | null;
158
+ /**
159
+ * End of the newest published media segment in seconds (the live edge), or `null` when unknown.
160
+ * Report this when the engine's seekable range stops short of the published playlist end;
161
+ * AVFoundation, for example, ends `seekableTimeRanges` one hold-back before the edge. If omitted,
162
+ * the live start positioning uses {@link seekableEnd} as the edge.
163
+ */
164
+ readonly liveEdge?: number | null;
165
+ /** Declared HLS EXT-X-TARGETDURATION in seconds, not average segment length; null when unknown. */
166
+ readonly targetDuration?: number | null;
167
+ /** False while play expresses intent but the content timeline is not yet ready for a startup seek. */
168
+ readonly playbackReady?: boolean;
169
+ /**
170
+ * Ask the engine to begin the upcoming live playback `targetDurations` declared target
171
+ * durations behind the live edge, before the first frame, instead of the SDK seeking after it.
172
+ * `fallbackTargetDuration` (seconds) applies when the engine cannot read the playlist's.
173
+ * `null` withdraws the request. Return `false` when the engine cannot honour it for the
174
+ * upcoming start; the SDK then seeks after the first frame. Omit when unsupported.
175
+ */
176
+ requestLiveStartOffset?(targetDurations: number | null, fallbackTargetDuration: number | null): boolean;
138
177
  /**
139
178
  * Playback rate (`1` = normal). Used to correct drift while content continues behind an
140
179
  * ad with `continueContentDuringBreak`. Report the engine's current rate, not just the last
@@ -149,6 +188,11 @@ export interface PlayerAdapter {
149
188
  * Resolve only when the element is free; do not destroy the adapter. The SDK restores
150
189
  * content with `load()` when the break ends. Omit this method if your player supports
151
190
  * sharing the element without an explicit release, as HLS.js does.
191
+ *
192
+ * The same method is called on the ad adapter that `createAdAdapter(container, video)` built
193
+ * for the content element, right before content is reloaded at break end. Leave the ad media
194
+ * on the element there: the content engine's `load()` replaces it in one step, and an element
195
+ * without a resource closes Safari's picture-in-picture window.
152
196
  */
153
197
  releaseMediaElement?(): void | Promise<void>;
154
198
  /**
@@ -1 +1 @@
1
- export {};
1
+ export { preparePresentation, getPreparedPresentation, disposePreparedPresentation } from '../services/adPlayer/PreparedPresentation';
@@ -1 +1 @@
1
- export{};
1
+ export{preparePresentation,getPreparedPresentation,disposePreparedPresentation}from"../services/adPlayer/PreparedPresentation";
@@ -9,9 +9,11 @@
9
9
  export type { BreakManifest, Break, BreakVariant, SingleBreakVariant, DoubleBreakVariant, LshapeAdBreakVariant, LshapeContentBreakVariant, OverlayBreakVariant, AssetWithCompanion, OverlayPosition, OverlaySize, Asset, StaticAsset, VendorAsset, Polling, Controls, Targeting, Interaction, AssetUri, EventTrigger, BreakPosition, } from '../types/BreakManifest';
10
10
  export { BreakFormat, AssetType, MediaType, Vendor, Timebase, DeviceType, BreakEvent, isEventTrigger, isPauseBreak, } from '../types/BreakManifest';
11
11
  export { parseBreakManifest, SUPPORTED_MANIFEST_MAJOR_VERSION, } from '../services/parseBreakManifest';
12
- export type { AdPreloadMode, AdInsertionMode, AdInsertionType, OptiViewAdsMode, } from '../types/OptiViewAdsConfig';
12
+ export type { AdPreloadMode, AdBreakContentRecovery, AdInsertionMode, AdInsertionType, OptiViewAdsMode, } from '../types/OptiViewAdsConfig';
13
13
  export type { ResolvedPreloadMode } from '../services/detectPreloadMode';
14
14
  export { resolvePreloadMode, isSingleDecoderUserAgent } from '../services/detectPreloadMode';
15
+ export type { ResolvedContentRecovery } from '../services/detectContentRecovery';
16
+ export { resolveContentRecovery, isRecreateAfterBreakUserAgent, } from '../services/detectContentRecovery';
15
17
  export type { ResolvedInsertionMode, MediaSourceCapabilities, } from '../services/detectInsertionMode';
16
18
  export { resolveInsertionMode, isSharedElementUserAgent, isSingleSurfaceWebDevice, } from '../services/detectInsertionMode';
17
19
  export { detectDeviceType } from '../services/detectDeviceType';
@@ -1 +1 @@
1
- export{BreakFormat,AssetType,MediaType,Vendor,Timebase,DeviceType,BreakEvent,isEventTrigger,isPauseBreak}from"../types/BreakManifest";export{parseBreakManifest,SUPPORTED_MANIFEST_MAJOR_VERSION}from"../services/parseBreakManifest";export{resolvePreloadMode,isSingleDecoderUserAgent}from"../services/detectPreloadMode";export{resolveInsertionMode,isSharedElementUserAgent,isSingleSurfaceWebDevice}from"../services/detectInsertionMode";export{detectDeviceType}from"../services/detectDeviceType";export{buildGamPodUrl,isGamVendorParameters}from"../services/GamPodUrlBuilder";export{SDK_VERSION}from"../generated/version";
1
+ export{BreakFormat,AssetType,MediaType,Vendor,Timebase,DeviceType,BreakEvent,isEventTrigger,isPauseBreak}from"../types/BreakManifest";export{parseBreakManifest,SUPPORTED_MANIFEST_MAJOR_VERSION}from"../services/parseBreakManifest";export{resolvePreloadMode,isSingleDecoderUserAgent}from"../services/detectPreloadMode";export{resolveContentRecovery,isRecreateAfterBreakUserAgent}from"../services/detectContentRecovery";export{resolveInsertionMode,isSharedElementUserAgent,isSingleSurfaceWebDevice}from"../services/detectInsertionMode";export{detectDeviceType}from"../services/detectDeviceType";export{buildGamPodUrl,isGamVendorParameters}from"../services/GamPodUrlBuilder";export{SDK_VERSION}from"../generated/version";
@@ -4,6 +4,7 @@ import { AdInsertionType, CreateAdAdapter, DoubleBoxAudio, GamConfig } from '../
4
4
  import { AssetParameterMacros } from './assetParameterMacros';
5
5
  import type { AssetParameterMacroUpdates } from '../types/OptiViewAdsConfig';
6
6
  import { ResolvedPreloadMode } from './detectPreloadMode';
7
+ import { ResolvedContentRecovery } from './detectContentRecovery';
7
8
  import { ResolvedInsertionMode } from './detectInsertionMode';
8
9
  import type { GamSessionIdentity } from './resolveGamVendorConfiguration';
9
10
  import { type NoPlayableAssetReason } from './AdBreakSequencer';
@@ -98,19 +99,13 @@ export declare class AdPlayerController {
98
99
  private readonly assetParameters;
99
100
  private readonly gamPodBridge;
100
101
  private readonly adStage;
102
+ private destroyed;
101
103
  private readonly preloader;
102
104
  private readonly assetPlayback;
103
105
  private readonly breakSequenceDriver;
104
106
  private readonly variantSelector;
105
107
  private readonly adPlayerEvents;
106
108
  private get gamEventCallbacks();
107
- /** Grace before the live resume releases the scheduler's reload guard — see endBreak(). */
108
- private readonly RESUME_GUARD_RELEASE_GRACE_MS;
109
- /**
110
- * The panel frees the displaced decoder asynchronously; resuming in the same task
111
- * intermittently fails with MEDIA_ERR_DECODE on Tizen — see endBreak().
112
- */
113
- private readonly SINGLE_DECODER_RESUME_DELAY_MS;
114
109
  /** Post-restore progress check — see armSharedRestoreWatchdog(). Mirrors the iOS runtime. */
115
110
  private debug;
116
111
  /**
@@ -153,6 +148,12 @@ export declare class AdPlayerController {
153
148
  private contentVideoMutationObserver;
154
149
  private preloadMode;
155
150
  private insertionMode;
151
+ private readonly recoveryDeps;
152
+ /**
153
+ * Bumped on every hard endBreak, on destroy() and when a new break starts, so an in-flight
154
+ * async resume (pipeline recreate grace) abandons itself instead of acting on a dead break.
155
+ */
156
+ private resumeGeneration;
156
157
  /**
157
158
  * Manifest-spec platform-capability fallback: on handheld/tablet web a `double` break renders
158
159
  * as a single fullscreen ad, while the reported format stays `double`.
@@ -213,7 +214,7 @@ export declare class AdPlayerController {
213
214
  private audioFocus;
214
215
  constructor(contentPlayer: PlayerAdapter, container: HTMLElement, playerContainer: HTMLElement | undefined, createAdAdapter: CreateAdAdapter, debug?: boolean, gamConfig?: GamConfig, preloadMode?: ResolvedPreloadMode, insertionMode?: ResolvedInsertionMode, adBreakCutSafetyMarginSec?: number, doubleBoxAudio?: DoubleBoxAudio, singleSurfaceDevice?: boolean,
215
216
  /** Injected so drift correction is deterministic under fake timers; reuses the scheduler's `Clock`. */
216
- clock?: Clock);
217
+ clock?: Clock, contentRecovery?: ResolvedContentRecovery);
217
218
  setGamEventCallbacks(callbacks: GamEventCallbacks): void;
218
219
  setDiagnoseHandler(fn: (code: string, message: string, context?: Record<string, unknown>) => void): void;
219
220
  private diagnose;
@@ -232,6 +233,8 @@ export declare class AdPlayerController {
232
233
  private clearContentGate;
233
234
  /** `null` disables chaining: breaks then always hard-end regardless of how close the next one is. */
234
235
  setChainResolver(resolver: ((currentBreakId: string) => Break | null) | null): void;
236
+ /** {@link ContentResumeCoordinator.setCueAnchorResolver}. */
237
+ setResumeCueAnchorResolver(resolver: ((breakInfo: Break) => number | null) | null): void;
235
238
  /** Only wired by the SDK in debug mode, so production reports keep their shape. */
236
239
  setTransitionPhaseReporter(reporter: ((name: string) => void) | null): void;
237
240
  /** No-op when no reporter is wired or no transition is in flight. */
@@ -274,7 +277,6 @@ export declare class AdPlayerController {
274
277
  /** Always creates a fresh IMA session. */
275
278
  private isGamPodAsset;
276
279
  private isExpandingPodAsset;
277
- private beginGamPodTracking;
278
280
  private fallBackToPodLevelReporting;
279
281
  private resetGamPodTracking;
280
282
  private emitGamPodSteps;
@@ -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 l,resolveBreakFormat as d}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{AssetPlayback as S}from"./adPlayer/AssetPlayback";import{BreakSequenceDriver as B}from"./adPlayer/BreakSequenceDriver";import{VariantSelector as E}from"./adPlayer/VariantSelector";import{AdPlayerEvents as b}from"./adPlayer/AdPlayerEvents";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,l="parallel",d="overlay",h=s,u=a,T=!1,F=c){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.RESUME_GUARD_RELEASE_GRACE_MS=2e3,this.SINGLE_DECODER_RESUME_DELAY_MS=300,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.singleSurfaceDevice=!1,this.currentSelectedFormat=void 0,this.audioFocus=null,this.state=m(),this.state.playerContainer=r??null,this.clock=F,this.singleSurfaceDevice=T,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=l,this.insertionMode=d,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.state.contentPositionAtBreakStart=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.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),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 E(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 S(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),beginGamPodTracking:e=>this.beginGamPodTracking(e),recordAdProgress:e=>this.adPlayerEvents.recordAdProgress(e),reportPhase:e=>this.reportPhase(e),armAdStartBudget:e=>this.armAdStartBudget(e),remainingAdStartBudgetMs:()=>this.remainingAdStartBudgetMs(),loadWithinBudget:e=>this.loadWithinBudget(e),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 B(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 b(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:()=>this.resumeCoordinator.maybePrepositionContentForResume(),maybeCatchUpContentForResume:e=>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}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)}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)}beginGamPodTracking(e){this.gamPodBridge.beginGamPodTracking(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?d(this.currentBreak):void 0)}async playBreak(t,s,a){if(this.state.preloadGeneration++,!this.sharedElementPlayer.beginSharedActivity())return;this.releaseContentHold(),this.rebindContentElementIfSwapped();const n=a?.effectiveDurationSec??null;this.effectiveBreakDurationSec=null!==n&&n>0?n:null;const l=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 d=this.getVariant(t);if(!d)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(d.format),u=r(t),c=this.shouldPauseContent(d.format)&&"ok"===h&&!u;c||u||this.state.continueRefusalReported||!this.shouldPauseContent(d.format)||(this.state.continueRefusalReported=!0,this.diagnose("DA-CONTINUE-PLAYOUT-REFUSED",`Content will be paused for breaks this session: ${h}`,{reason:h,format:d.format})),this.audioFocus=d.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(d.format)?(this.state.contentPositionAtBreakStart=this.contentPlayer.currentTime,this.resumeCoordinator.resetBreakResumeState(),c?(this.contentPaused=!1,this.resumeCoordinator.beginContinueContentPlayout()):(this.contentPaused=!0,this.gateContentForBreak())):this.contentPaused=!1,this.applyLayout(d),d.format===e.LSHAPE_CONTENT)return this.renderLshapeContentBackdrop(d),void(l&&l>0?(this.log("Starting duration timer:",l,"seconds"),this.durationTimer=setTimeout(()=>{this.log("Duration timer expired, ending break"),this.endBreak()},1e3*l)):this.endBreak());this.firstFrameGateActive||(this.show(),this.reapplyAdContainerLayout(d));if(0===this.getAssets(t).length)return this.log("No assets in break, ending immediately"),void this.endBreak();{const e=Math.max(0,l||0)+this.adBreakCutSafetyMarginSec;this.log("Starting break-cut timer:",e,"seconds"),this.durationTimer=setTimeout(()=>{this.log("Break-cut timer expired, ending break"),this.firstFrameRejector?this.onAdError(new Error("Break cut before first frame rendered")):this.sequencer&&this.currentBreak&&this.isPlaying?(this.callbacks?.onBreakCut?.(this.currentBreak),this.drive(this.sequencer.onOutcome({kind:"break-elapsed"}))):this.endBreak()},1e3*e)}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??d(e)}getVariant(e){return this.variantSelector.getVariant(e)}applyLayout(e){this.adStage.applyLayout(e)}restoreLayout(e){this.adStage.restoreLayout(e)}getAssets(e){return l(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),this.durationTimer&&(clearTimeout(this.durationTimer),this.durationTimer=null),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 Error(`Break ${a.id} has no playable variant (${e})`)),this.callbacks?.onChainedBreakSkipped?.(a),a=null)}if(a)this.advanceToChainedBreak(e,a);else{if(this.currentSelectedFormat=void 0,this.resumeCoordinator.endContinueContentPlayout(),this.restorePictureInPictureToContent(),this.isPlaying=!1,this.currentBreak=null,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)}if("single-decoder"===this.preloadMode&&this.adPlayer?.unload?.(),this.contentPaused&&r(e))this.contentPaused=!1,this.clearContentGate();else if(this.contentPaused){this.contentPaused=!1,this.clearContentGate(this.resumeHandoverInMotion);const r=this.state.earlyReturnResumeOffsetSec,s=this.breakTimebase===t.WALLCLOCK,a=()=>{s&&this.callbacks?.onContentReloading?.(!0),this.resumeCoordinator.applyResumeSeek(e,r),this.contentPlayer.play().catch(e=>{this.log("Content resume failed:",e)}).finally(()=>{s&&setTimeout(()=>this.callbacks?.onContentReloading?.(!1),this.RESUME_GUARD_RELEASE_GRACE_MS)})};"single-decoder"===this.preloadMode?setTimeout(a,this.SINGLE_DECODER_RESUME_DELAY_MS):a()}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),this.durationTimer&&(clearTimeout(this.durationTimer),this.durationTimer=null),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,this.durationTimer&&(clearTimeout(this.durationTimer),this.durationTimer=null),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),this.durationTimer&&(clearTimeout(this.durationTimer),this.durationTimer=null),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){return this.preloader.loadWithinBudget(e)}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(g(this.state),this.sharedElementPlayer.beginSharedActivity()){if(this.adStage.destroy(),this.resumeCoordinator.cancelResumeLandedProbe(),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(),this.durationTimer&&(clearTimeout(this.durationTimer),this.durationTimer=null),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.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,this.playerContainerCreatedBySDK)for(;this.playerContainer.firstChild;)this.container.appendChild(this.playerContainer.firstChild);else this.container.appendChild(this.playerContainer),this.playerContainer.style.cssText=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),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 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 b}from"./adPlayer/BreakSequenceDriver";import{VariantSelector as E}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 E(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 b(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)}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)}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.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;
@@ -168,7 +168,10 @@ export declare class BreakScheduler {
168
168
  stop(): void;
169
169
  completeBreak(breakId: string): void;
170
170
  /** Bracket a content RELOAD so the new stream's start is not read as a backward seek. `false` also discards the stale previous position. */
171
+ private contentReloading;
172
+ private startupSeeking;
171
173
  setContentReloading(active: boolean): void;
174
+ setStartupSeeking(active: boolean): void;
172
175
  /**
173
176
  * The runtime is about to resume-seek content to `targetSeconds` after a break ending at
174
177
  * `breakEndSeconds`. Arms a guard so the small backward step is not read as a DVR seek-back;
@@ -184,8 +187,8 @@ export declare class BreakScheduler {
184
187
  /**
185
188
  * Advance the schedule NOW because a cue reached the playhead: the 250ms tick discovers a start
186
189
  * ~125ms late on average, an adapter reporting PRESENTATION knows the instant. Runs
187
- * {@link checkBreaks} so every tick guard applies unchanged. A cue cannot present before the
188
- * playhead reaches it, so this can only fire on time, never early.
190
+ * {@link checkBreaks} so every tick guard applies unchanged, including the timing check against
191
+ * the tracker's media time: a segment-anchored emsg cue presenting at its segment start is ignored.
189
192
  * Returns the id of the break this armed, or null.
190
193
  */
191
194
  notifyCuePresented(pts: number): string | null;
@@ -1 +1 @@
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 o}from"../types/OptiViewAdsConfig";import{PTS_MATCH_TOLERANCE_SECONDS as l}from"./MetadataCueTracker";import{debugLog as h}from"../diagnostics/debugLog";import{createBreakTimingState as k,getBreakStartTime as c,getCurrentTime as u,secondsUntilBreak as b}from"./breakTiming";import{RewindRearm as g}from"./RewindRearm";export const systemClock={now:()=>Date.now()};export var BreakState;!function(e){e.PENDING="pending",e.CHAINED="chained",e.ACTIVE="active",e.COMPLETED="completed",e.SKIPPED="skipped"}(BreakState||(BreakState={}));export class BreakScheduler{constructor(e,t=!1,a={enabled:!1,maxGapSeconds:0},i=systemClock,r={enabled:!1,minBreakDurationSeconds:0},s=null,n=d,l=null,h=o){this.breaks=new Map,this.timing=k(),this.checkInterval=null,this.onBreakStart=null,this.onBreakApproaching=null,this.onBreakWarning=null,this.onBreakAborted=null,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.player=e,this.debug=t,this.chainingEnabled=a.enabled,this.maxChainGapMs=1e3*Math.max(0,a.maxGapSeconds),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,h);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 g({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 a=this.breaks.get(e.id);if(!a||a.state!==BreakState.PENDING)break;a.state=BreakState.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,[BreakState.PENDING,BreakState.CHAINED]):null}activateChainedBreak(e){const t=this.breaks.get(e);t&&(t.state=BreakState.ACTIVE)}findSuccessor(e,t=[BreakState.PENDING]){const a=this.getBreakStartTime(e);if(null===a)return null;const i=a+1e3*(e.duration??0);let r=null;for(const s of this.breaks.values()){if(s.break.id===e.id)continue;if(!t.includes(s.state))continue;const n=this.getBreakStartTime(s.break);if(null===n)continue;if(n<=a)continue;const d=n-i;d>this.maxChainGapMs||(d<-this.TIMING_TOLERANCE_MS||(!r||n<r.start)&&(r={break:s.break,start:n}))}return r?.break??null}updateManifest(e){this.timing.timebase=e.timebase,this.rewind.setAdStartDelayMs(1e3*Math.max(0,e.adStartDelay??0));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===BreakState.PENDING&&(e.break=t):(this.breaks.set(t.id,{break:t,state:BreakState.PENDING}),this.log(`📅 Break scheduled: "${t.id}" at ${this.describeStart(t)}`))}const t=new Set(e.breaks.map(e=>e.id));for(const[e,a]of this.breaks)t.has(e)||a.state!==BreakState.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?.(a.break));this.cleanupBreaks(t)}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.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)}describeStart(e){const t=r(e);if(null!==t)return t>0?`playback start + ${t}s`:"playback start";const a=i(e);return null!==a?a>0?`playback end + ${a}s`:"playback end":"string"==typeof e.start?new Date(e.start).toLocaleTimeString():String(e.start)}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()))}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){this.onBreakStart=e,this.onBreakApproaching=t??null,this.onBreakWarning=a??null,this.onBreakAborted=i??null,this.checkInterval&&clearInterval(this.checkInterval),this.checkInterval=setInterval(()=>{this.tick()},250),this.log("Scheduler started")}tick(){this.checkBreaks()}stop(){this.checkInterval&&(clearInterval(this.checkInterval),this.checkInterval=null),this.onBreakStart=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.preloadedBreakIds.delete(e))}setContentReloading(e){this.rewind.setContentReloading(e)}notifyResumeSeek(e,t){this.rewind.notifyResumeSeek(e,t)}notifyViewerSeek(){this.rewind.notifyViewerSeek()}cleanupBreaks(e){const t=[];for(const[a,i]of this.breaks)i.state!==BreakState.COMPLETED&&i.state!==BreakState.SKIPPED&&(e.has(a)||i.state===BreakState.ACTIVE)||t.push(a);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===BreakState.ACTIVE)return e.break;return null}getSecondsUntilBreak(e){const t=this.breaks.get(e);if(!t||t.state!==BreakState.PENDING)return null;const a=this.getCurrentTime();if(null===a)return null;const i=this.getBreakStartTime(t.break);return null===i?null:b(i,a)}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===BreakState.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===BreakState.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(){const e=this.getCurrentTime();this.rewind.trackPlayedTime(e);const a=this.rewind.isAdStartDelayActive();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===BreakState.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!==BreakState.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 o=this.getBreakStartTime(s.break);if(null===o)continue;const l=e-o,h=Math.round(-l/1e3);if(this.checkWarnings(s.break,h),h>0&&h<=15&&h%2==0&&this.log(`⏱️ Break "${s.break.id}" starts in ${h}s`),h>0&&h<=this.PRELOAD_AHEAD_SECONDS&&this.maybePreload(s.break,`${h}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)`),s.state=BreakState.SKIPPED,null===this.cueTracker&&this.retiredBreaks.set(s.break.id,s.break);break}if(null!==this.minSeenTime&&o<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)`),s.state=BreakState.SKIPPED,null===this.cueTracker&&this.retiredBreaks.set(s.break.id,s.break);break}this.log(`🎬 BREAK TRIGGERED: "${s.break.id}"`),s.state=BreakState.ACTIVE,this.onBreakStart&&this.onBreakStart(s.break,{tuneIn:!1,elapsedSec:e/1e3,remainingSec:t/1e3});break}if(l>this.TIMING_TOLERANCE_MS){const t=o+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=BreakState.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)`),s.state=BreakState.SKIPPED,null===this.cueTracker&&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(e.state=BreakState.SKIPPED);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=BreakState.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=BreakState.ACTIVE,this.onBreakStart&&this.onBreakStart(e.break,{tuneIn:!1,elapsedSec:0,remainingSec:e.break.duration??0}))}isAdStartDelayActive(){return this.rewind.isAdStartDelayActive()}getCurrentTime(){return u(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 s(e.start)?null:c(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.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.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&&h("[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 o}from"../types/OptiViewAdsConfig";import{PTS_MATCH_TOLERANCE_SECONDS as l}from"./MetadataCueTracker";import{debugLog as h}from"../diagnostics/debugLog";import{createBreakTimingState as k,getBreakStartTime as c,getCurrentTime as u,secondsUntilBreak as b}from"./breakTiming";import{RewindRearm as g}from"./RewindRearm";export const systemClock={now:()=>Date.now()};export var BreakState;!function(e){e.PENDING="pending",e.CHAINED="chained",e.ACTIVE="active",e.COMPLETED="completed",e.SKIPPED="skipped"}(BreakState||(BreakState={}));export class BreakScheduler{constructor(e,t=!1,a={enabled:!1,maxGapSeconds:0},i=systemClock,r={enabled:!1,minBreakDurationSeconds:0},s=null,n=d,l=null,h=o){this.breaks=new Map,this.timing=k(),this.checkInterval=null,this.onBreakStart=null,this.onBreakApproaching=null,this.onBreakWarning=null,this.onBreakAborted=null,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=a.enabled,this.maxChainGapMs=1e3*Math.max(0,a.maxGapSeconds),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,h);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 g({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 a=this.breaks.get(e.id);if(!a||a.state!==BreakState.PENDING)break;a.state=BreakState.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,[BreakState.PENDING,BreakState.CHAINED]):null}activateChainedBreak(e){const t=this.breaks.get(e);t&&(t.state=BreakState.ACTIVE)}findSuccessor(e,t=[BreakState.PENDING]){const a=this.getBreakStartTime(e);if(null===a)return null;const i=a+1e3*(e.duration??0);let r=null;for(const s of this.breaks.values()){if(s.break.id===e.id)continue;if(!t.includes(s.state))continue;const n=this.getBreakStartTime(s.break);if(null===n)continue;if(n<=a)continue;const d=n-i;d>this.maxChainGapMs||(d<-this.TIMING_TOLERANCE_MS||(!r||n<r.start)&&(r={break:s.break,start:n}))}return r?.break??null}updateManifest(e){this.timing.timebase=e.timebase,this.rewind.setAdStartDelayMs(1e3*Math.max(0,e.adStartDelay??0));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===BreakState.PENDING&&(e.break=t):(this.breaks.set(t.id,{break:t,state:BreakState.PENDING}),this.log(`📅 Break scheduled: "${t.id}" at ${this.describeStart(t)}`))}const t=new Set(e.breaks.map(e=>e.id));for(const[e,a]of this.breaks)t.has(e)||a.state!==BreakState.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?.(a.break));this.cleanupBreaks(t)}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.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)}describeStart(e){const t=r(e);if(null!==t)return t>0?`playback start + ${t}s`:"playback start";const a=i(e);return null!==a?a>0?`playback end + ${a}s`:"playback end":"string"==typeof e.start?new Date(e.start).toLocaleTimeString():String(e.start)}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()))}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){this.onBreakStart=e,this.onBreakApproaching=t??null,this.onBreakWarning=a??null,this.onBreakAborted=i??null,this.checkInterval&&clearInterval(this.checkInterval),this.checkInterval=setInterval(()=>{this.tick()},250),this.log("Scheduler started")}tick(){this.checkBreaks()}stop(){this.checkInterval&&(clearInterval(this.checkInterval),this.checkInterval=null),this.onBreakStart=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.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()}cleanupBreaks(e){const t=[];for(const[a,i]of this.breaks)i.state!==BreakState.COMPLETED&&i.state!==BreakState.SKIPPED&&(e.has(a)||i.state===BreakState.ACTIVE)||t.push(a);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===BreakState.ACTIVE)return e.break;return null}getSecondsUntilBreak(e){const t=this.breaks.get(e);if(!t||t.state!==BreakState.PENDING)return null;const a=this.getCurrentTime();if(null===a)return null;const i=this.getBreakStartTime(t.break);return null===i?null:b(i,a)}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===BreakState.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===BreakState.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.startupSeeking)return;const e=this.getCurrentTime();this.rewind.trackPlayedTime(e);const a=this.rewind.isAdStartDelayActive();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===BreakState.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!==BreakState.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 o=this.getBreakStartTime(s.break);if(null===o)continue;const l=e-o,h=Math.round(-l/1e3);if(this.checkWarnings(s.break,h),h>0&&h<=15&&h%2==0&&this.log(`⏱️ Break "${s.break.id}" starts in ${h}s`),h>0&&h<=this.PRELOAD_AHEAD_SECONDS&&this.maybePreload(s.break,`${h}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)`),s.state=BreakState.SKIPPED,null===this.cueTracker&&this.retiredBreaks.set(s.break.id,s.break);break}if(null!==this.minSeenTime&&o<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)`),s.state=BreakState.SKIPPED,null===this.cueTracker&&this.retiredBreaks.set(s.break.id,s.break);break}this.log(`🎬 BREAK TRIGGERED: "${s.break.id}"`),s.state=BreakState.ACTIVE,this.onBreakStart&&this.onBreakStart(s.break,{tuneIn:!1,elapsedSec:e/1e3,remainingSec:t/1e3});break}if(l>this.TIMING_TOLERANCE_MS){const t=o+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=BreakState.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)`),s.state=BreakState.SKIPPED,null===this.cueTracker&&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(e.state=BreakState.SKIPPED);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=BreakState.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=BreakState.ACTIVE,this.onBreakStart&&this.onBreakStart(e.break,{tuneIn:!1,elapsedSec:0,remainingSec:e.break.duration??0}))}isAdStartDelayActive(){return this.rewind.isAdStartDelayActive()}getCurrentTime(){return u(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 s(e.start)?null:c(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.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.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&&h("[OptiViewAds:BreakScheduler]",...e)}}
@@ -18,13 +18,20 @@ export declare class CmcdAdReporter {
18
18
  private sessionKeys;
19
19
  private activeBreakId;
20
20
  private breakBeginTimestamp;
21
+ private breakAvailableMs;
22
+ private breakRequestedMs;
21
23
  private firstAdReported;
22
24
  /** Playable (non-companion) ad milliseconds delivered so far in the break. */
23
25
  private breakFilledMs;
24
26
  /** Milliseconds of ad media actually watched so far in the break. */
25
27
  private breakWatchedMs;
26
28
  private activeAdKeys;
29
+ /** The active ad's paired companion, remembered for the session-end `ae`. */
30
+ private activeAdCompanion;
27
31
  private activeAdAssetId;
32
+ private activeAdIsVendor;
33
+ private activeAdBaseSec;
34
+ private breakLastTimeSec;
28
35
  /**
29
36
  * The break's first `as` payload, held until the ad renders its first frame
30
37
  * (the first `adtimeupdate` with `currentTime > 0`) so `brttf` measures
@@ -34,10 +41,19 @@ export declare class CmcdAdReporter {
34
41
  private pendingAdStart;
35
42
  private activeAdWatchedSec;
36
43
  private activeAdDeclaredSec;
44
+ private activeAdIsVast;
45
+ /** The VAST creative duration the ad player resolved, from `adtimeupdate`. */
46
+ private activeAdResolvedSec;
37
47
  private skipRequestedBreakId;
38
48
  private abortedBreakId;
39
49
  private cutBreakId;
40
50
  private erroredAssetId;
51
+ /**
52
+ * Break closed by `onSessionEnd`. Teardown can still dispatch a late
53
+ * `adend`/`adbreakend` for it (e.g. a channel switch stops the old break
54
+ * after the new session started); those must not double-emit.
55
+ */
56
+ private finalizedBreakId;
41
57
  constructor(getHandle: () => LensHandle | null, log: (...args: unknown[]) => void);
42
58
  /**
43
59
  * Seed the session-scoped keys from the fetched manifest: SDK version,
@@ -46,6 +62,7 @@ export declare class CmcdAdReporter {
46
62
  onSessionStart(manifest: BreakManifest): void;
47
63
  /** Clear all telemetry state and the heartbeat payload. */
48
64
  onSessionEnd(): void;
65
+ private finalizeActiveBreak;
49
66
  /** The viewer requested a skip — the next `adend` for this break is a skip. */
50
67
  onSkipRequested(breakId: string): void;
51
68
  /** The break is being aborted (early return / teardown) — the next `adend` is an abort. */
@@ -64,16 +81,29 @@ export declare class CmcdAdReporter {
64
81
  */
65
82
  private emitPendingAdStart;
66
83
  private onAdEnd;
84
+ private emitAdEnd;
67
85
  private onBreakEnd;
86
+ private emitBreakEnd;
68
87
  private onMilestone;
69
88
  private onClick;
70
89
  private onAdError;
71
90
  private emitCustomWithAdContext;
91
+ /**
92
+ * The seconds the active ad fills: the VAST creative duration the ad player
93
+ * resolved, within the manifest-declared slot; the declared duration when
94
+ * the player resolved none.
95
+ */
96
+ private activeAdFilledSec;
97
+ /**
98
+ * The ad keys for a milestone/click/error row: the full `as` key set when the
99
+ * event's asset is the active ad (same match rule as `adtimeupdate`),
100
+ * otherwise the minimal brid/adasid(+adid) identity row.
101
+ */
102
+ private adContextKeys;
72
103
  private adEndReason;
73
104
  /**
74
- * Sum the declared durations of the playable ads of the selected variant
75
- * (companions excluded), clamped to what is actually available. Null when
76
- * no asset declares a duration — nothing meaningful to request.
105
+ * Request the whole available window when a playable asset has no duration.
106
+ * Otherwise sum declared durations and clamp the result to availability.
77
107
  */
78
108
  private requestedPlayableMs;
79
109
  /** Re-derive the heartbeat context payload: session keys + active break/ad. */