@dolby-optiview/ads-sdk-core 1.1.1 → 1.2.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 (88) hide show
  1. package/dist/OptiViewAds.d.ts +8 -4
  2. package/dist/OptiViewAds.js +1 -1
  3. package/dist/OptiViewAdsExternalVendors.d.ts +47 -0
  4. package/dist/OptiViewAdsExternalVendors.js +1 -0
  5. package/dist/generated/diagnosticCodes.d.ts +72 -2
  6. package/dist/generated/diagnosticCodes.js +1 -1
  7. package/dist/generated/version.d.ts +1 -1
  8. package/dist/generated/version.js +1 -1
  9. package/dist/id3/index.d.ts +1 -0
  10. package/dist/id3/index.js +1 -1
  11. package/dist/id3/parseId3TextFrames.d.ts +8 -0
  12. package/dist/id3/parseId3TextFrames.js +1 -0
  13. package/dist/index.d.ts +8 -3
  14. package/dist/index.js +1 -1
  15. package/dist/interfaces/PlayerAdapter.d.ts +5 -0
  16. package/dist/services/AdBreakSequencer.js +1 -1
  17. package/dist/services/AdPlayerController.d.ts +2 -0
  18. package/dist/services/AdPlayerController.js +1 -1
  19. package/dist/services/BreakScheduler.d.ts +31 -56
  20. package/dist/services/BreakScheduler.js +1 -1
  21. package/dist/services/BreakSchedulerTypes.d.ts +55 -0
  22. package/dist/services/BreakSchedulerTypes.js +1 -0
  23. package/dist/services/ExternalVendorConfigurationTracker.d.ts +13 -0
  24. package/dist/services/ExternalVendorConfigurationTracker.js +1 -0
  25. package/dist/services/GamStreamManager.d.ts +6 -0
  26. package/dist/services/GamStreamManager.js +1 -1
  27. package/dist/services/ImaMetadataDeduplicator.d.ts +5 -0
  28. package/dist/services/ImaMetadataDeduplicator.js +1 -0
  29. package/dist/services/SsaiController.d.ts +2 -0
  30. package/dist/services/SsaiController.js +1 -1
  31. package/dist/services/adPlayer/AdPlayerEvents.js +1 -1
  32. package/dist/services/adPlayer/AdPlayerState.d.ts +13 -0
  33. package/dist/services/adPlayer/AdPlayerState.js +1 -1
  34. package/dist/services/adPlayer/AdPreloader.js +1 -1
  35. package/dist/services/adPlayer/AdStage.d.ts +7 -3
  36. package/dist/services/adPlayer/AdStage.js +1 -1
  37. package/dist/services/adPlayer/AssetParameterResolver.d.ts +2 -0
  38. package/dist/services/adPlayer/AssetParameterResolver.js +1 -1
  39. package/dist/services/adPlayer/AssetPlayback.js +1 -1
  40. package/dist/services/adPlayer/ContentResumeCoordinator.d.ts +10 -3
  41. package/dist/services/adPlayer/ContentResumeCoordinator.js +1 -1
  42. package/dist/services/adPlayer/GamPodBridge.js +1 -1
  43. package/dist/services/adPlayer/SharedElementBreakPlayer.js +1 -1
  44. package/dist/services/adPlayer/VariantSelector.js +1 -1
  45. package/dist/services/adPlayer/pdtClockResume.d.ts +57 -0
  46. package/dist/services/adPlayer/pdtClockResume.js +1 -0
  47. package/dist/services/assetParameterMacros.d.ts +0 -1
  48. package/dist/services/assetParameterMacros.js +1 -1
  49. package/dist/services/breakTiming.d.ts +2 -0
  50. package/dist/services/breakTiming.js +1 -1
  51. package/dist/services/channelSwitch.d.ts +3 -1
  52. package/dist/services/channelSwitch.js +1 -1
  53. package/dist/services/detectDeviceType.d.ts +7 -2
  54. package/dist/services/detectDeviceType.js +1 -1
  55. package/dist/services/diagnosticReport.d.ts +3 -0
  56. package/dist/services/diagnosticReport.js +1 -0
  57. package/dist/services/externalVendorConfigurationGetter.d.ts +12 -0
  58. package/dist/services/externalVendorConfigurationGetter.js +1 -0
  59. package/dist/services/matchTargeting.d.ts +19 -0
  60. package/dist/services/matchTargeting.js +1 -0
  61. package/dist/services/resolveDeliveryMode.d.ts +3 -1
  62. package/dist/services/resolveDeliveryMode.js +1 -1
  63. package/dist/services/resolveExternalVendorConfigurations.d.ts +20 -0
  64. package/dist/services/resolveExternalVendorConfigurations.js +1 -0
  65. package/dist/services/resolveGamVendorConfiguration.js +1 -1
  66. package/dist/services/resolveResumeClamp.d.ts +42 -0
  67. package/dist/services/resolveResumeClamp.js +1 -0
  68. package/dist/services/resolveTargetedUri.d.ts +2 -1
  69. package/dist/services/resolveTargetedUri.js +1 -1
  70. package/dist/services/selectVariant.d.ts +4 -0
  71. package/dist/services/selectVariant.js +1 -1
  72. package/dist/services/toPlaybackError.d.ts +1 -0
  73. package/dist/services/toPlaybackError.js +1 -0
  74. package/dist/services/wallclockBreakWindow.d.ts +41 -0
  75. package/dist/services/wallclockBreakWindow.js +1 -0
  76. package/dist/session/BreakLifecycle.d.ts +2 -0
  77. package/dist/session/BreakLifecycle.js +1 -1
  78. package/dist/session/SessionStarter.d.ts +6 -1
  79. package/dist/session/SessionStarter.js +1 -1
  80. package/dist/session/SessionState.d.ts +1 -0
  81. package/dist/session/SessionState.js +1 -1
  82. package/dist/types/BreakManifest.d.ts +39 -1
  83. package/dist/types/BreakManifest.js +1 -1
  84. package/dist/types/Events.d.ts +16 -1
  85. package/dist/types/ExternalVendorConfiguration.d.ts +5 -0
  86. package/dist/types/ExternalVendorConfiguration.js +1 -0
  87. package/dist/types/OptiViewAdsConfig.d.ts +2 -1
  88. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -1,11 +1,15 @@
1
1
  export { OptiViewAds } from './OptiViewAds';
2
+ export { OptiViewAdsExternalVendors, type OptiViewAdsExternalVendorsConfig, } from './OptiViewAdsExternalVendors';
2
3
  export type { PlayerAdapter, PlayerAdapterEvent, PlayerAdapterEventHandler, TimedMetadataCue, VideoQuality, } from './interfaces/PlayerAdapter';
3
- export type { BreakManifest, Break, BreakPosition, EventTrigger, BreakVariant, SingleBreakVariant, DoubleBreakVariant, LshapeAdBreakVariant, LshapeContentBreakVariant, OverlayBreakVariant, AssetWithCompanion, OverlayPosition, OverlaySize, Asset, StaticAsset, VastAsset, VendorAsset, Polling, Controls, Targeting, Interaction, AssetUri, DeliveryRule, VendorConfiguration, VendorConfigurationBase, GamVendorConfiguration, GamSgaiConfiguration, GamSsaiConfiguration, } from './types/BreakManifest';
4
- export { BreakFormat, AssetType, MediaType, Vendor, Timebase, DeviceType, DeliveryMode, BreakEvent, } from './types/BreakManifest';
4
+ export type { BreakManifest, Break, BreakPosition, EventTrigger, BreakVariant, SingleBreakVariant, DoubleBreakVariant, LshapeAdBreakVariant, LshapeContentBreakVariant, OverlayBreakVariant, AssetWithCompanion, OverlayPosition, OverlaySize, Asset, StaticAsset, VastAsset, VendorAsset, Polling, Controls, Targeting, OsVersionRange, Interaction, AssetUri, DeliveryRule, VendorConfiguration, VendorConfigurationBase, GamVendorConfiguration, GamSgaiConfiguration, GamSsaiConfiguration, } from './types/BreakManifest';
5
+ export type { ExternalVendorConfiguration } from './types/ExternalVendorConfiguration';
6
+ export { BreakFormat, AssetType, MediaType, Vendor, Timebase, DeviceType, Platform, Os, DeliveryMode, BreakEvent, } from './types/BreakManifest';
5
7
  export { isStaticAsset, isVastAsset, isVendorAsset, isGamVendorConfiguration, isEventTrigger, isPauseBreak, } from './types/BreakManifest';
6
8
  export { resolveDeliveryMode, resolveStitchedStreamVendor, SsaiUnavailableError, } from './services/resolveDeliveryMode';
7
9
  export type { DeliveryModeDecision } from './services/resolveDeliveryMode';
8
10
  export type { StitchedStreamVendor } from './services/resolveDeliveryMode';
11
+ export type { DeviceProfile, TargetingIssue, TargetingMatch } from './services/matchTargeting';
12
+ export { matchTargeting } from './services/matchTargeting';
9
13
  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
14
  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
15
  export type { StitcherMasterUrlParams } from './services/StitcherUrlBuilder';
@@ -21,6 +25,7 @@ export type { SsaiControllerOptions, SsaiControllerCallbacks } from './services/
21
25
  export { SsaiController } from './services/SsaiController';
22
26
  export type { ResolvedPreloadMode } from './services/detectPreloadMode';
23
27
  export { resolvePreloadMode, isSingleDecoderUserAgent } from './services/detectPreloadMode';
28
+ export { detectDeviceProfile } from './services/detectDeviceType';
24
29
  export type { ResolvedContentRecovery } from './services/detectContentRecovery';
25
30
  export { resolveContentRecovery, isRecreateAfterBreakUserAgent, } from './services/detectContentRecovery';
26
31
  export type { ResolvedInsertionMode, MediaSourceCapabilities, } from './services/detectInsertionMode';
@@ -45,4 +50,4 @@ export { parseBreakManifest, SUPPORTED_MANIFEST_MAJOR_VERSION, } from './service
45
50
  export { fetchWithTimeout, AUX_FETCH_TIMEOUT_MS } from './services/fetchWithTimeout';
46
51
  export type { GamVendorParameters } from './services/GamPodUrlBuilder';
47
52
  export { buildGamPodUrl, isGamVendorParameters } from './services/GamPodUrlBuilder';
48
- export type { OptiViewAdsEventType, OptiViewAdsEventHandler, OptiViewAdsEventMap, OptiViewAdsEvent, AdBreakBeginEvent, AdBreakEndEvent, AdBeginEvent, AdEndEvent, AdErrorEvent, AdFirstQuartileEvent, AdMidpointEvent, AdThirdQuartileEvent, AdTimeupdateEvent, WaitingEvent, PlayingEvent, VolumeChangeEvent, AdClickEvent, PlaybackSource, AdBreakPhase, AdBreakStatus, AdBreakStatusEvent, AdChannelChangeEvent, AdChannelChangeReason, } from './types/Events';
53
+ export type { OptiViewAdsEventType, OptiViewAdsEventHandler, OptiViewAdsEventMap, OptiViewAdsEvent, AdBreakBeginEvent, AdBreakEndEvent, AdBreakSkippedEvent, AdBreakSkipReason, AdBeginEvent, AdEndEvent, AdErrorEvent, AdFirstQuartileEvent, AdMidpointEvent, AdThirdQuartileEvent, AdTimeupdateEvent, WaitingEvent, PlayingEvent, VolumeChangeEvent, AdClickEvent, PlaybackSource, AdBreakPhase, AdBreakStatus, AdBreakStatusEvent, AdChannelChangeEvent, AdChannelChangeReason, } from './types/Events';
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_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";
1
+ export{OptiViewAds}from"./OptiViewAds";export{OptiViewAdsExternalVendors}from"./OptiViewAdsExternalVendors";export{BreakFormat,AssetType,MediaType,Vendor,Timebase,DeviceType,Platform,Os,DeliveryMode,BreakEvent}from"./types/BreakManifest";export{isStaticAsset,isVastAsset,isVendorAsset,isGamVendorConfiguration,isEventTrigger,isPauseBreak}from"./types/BreakManifest";export{resolveDeliveryMode,resolveStitchedStreamVendor,SsaiUnavailableError}from"./services/resolveDeliveryMode";export{matchTargeting}from"./services/matchTargeting";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{detectDeviceProfile}from"./services/detectDeviceType";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";
@@ -90,6 +90,11 @@ export interface PlayerAdapter {
90
90
  * (`DA-SHARED-ELEMENT-UNSUPPORTED`).
91
91
  */
92
92
  readonly sourceUrl?: string | null;
93
+ /**
94
+ * Called by the SDK once on each adapter returned by `createAdAdapter`, before its first `load()`.
95
+ * Lets an adapter enable player settings that only ad playback needs.
96
+ */
97
+ prepareForAdPlayback?(): void;
93
98
  /**
94
99
  * Optional: warm caches (manifest, optionally the first fragment) WITHOUT attaching media or
95
100
  * engaging a decoder, for single-decoder Smart TVs that cannot hold two MediaSources. Must not
@@ -1 +1 @@
1
- import{BreakFormat as t}from"../types/BreakManifest";import{KNOWN_BREAK_FORMATS as e,selectVariantDetailed as s,variantsOf as a}from"./selectVariant";export function selectVariant(t,a){return s(t,a??{playableFormats:e}).selected}export function resolveBreakFormat(t,e){return selectVariant(t,e)?.format}export function assetsOfVariant(e){if(!e)return[];switch(e.format){case t.SINGLE:case t.DOUBLE:case t.LSHAPE_AD:case t.LSHAPE_CONTENT:case t.OVERLAY:return e.assets;default:return[]}}export function extractAssets(t,e){return assetsOfVariant(selectVariant(t,e))}export function breakPlanEmptyReason(t,e,s={}){const a=r(t,e,s);return"empty"===a.mode?a.reason??null:null}function r(r,n,i={}){if(0===a(r).length)return{mode:"empty",reason:"no-variant",variant:null};const o=s(r,{deviceType:i.deviceType,playableFormats:"shared-element"===n?e:i.playableFormats}),d=o.selected,l=d??o.deviceQualified;if(!l)return{mode:"empty",reason:"no-qualifying-variant",variant:null};if("shared-element"===n){if(l.format===t.LSHAPE_CONTENT)return{mode:"empty",reason:"lshape-content-skipped",variant:l};const e=assetsOfVariant(l)[0];return e?{mode:"shared-single",asset:e,variant:l}:{mode:"empty",reason:"no-assets",variant:l}}if(d){if(d.format===t.LSHAPE_CONTENT)return{mode:"overlay-backdrop",variant:d};const e=assetsOfVariant(d);return e.length>0?{mode:"overlay-assets",assets:e,variant:d}:{mode:"empty",reason:"no-assets",variant:d}}if(l.format===t.LSHAPE_CONTENT)return{mode:"overlay-backdrop",variant:l};const h=assetsOfVariant(l)[0];return h?{mode:"overlay-assets",assets:[h],variant:l}:{mode:"empty",reason:"no-assets",variant:l}}export class AdBreakSequencer{constructor(t,e=()=>null,s={}){this.insertionMode=t,this.chainResolver=e,this.selection=s,this.currentBreak=null,this.plan={mode:"empty"},this.assetIndex=0,this.assetStarted=!1}planFormat(){return"variant"in this.plan?this.plan.variant?.format:void 0}beginBreak(t){if(this.currentBreak=t,this.plan=r(t,this.insertionMode,this.selection),this.assetIndex=0,this.assetStarted=!1,"empty"===this.plan.mode)return this.retireEmptyBreak(t,[],this.noticeFor(t));return{steps:[{type:"adbreakbegin",break:t,format:this.planFormat()}],action:this.startAction(this.plan)}}noticeFor(t){return"empty"===this.plan.mode&&this.plan.reason?[{breakId:t.id,reason:this.plan.reason,format:this.plan.variant?.format,declaredAssetCount:a(t).reduce((t,e)=>t+assetsOfVariant(e).length,0)}]:[]}retireEmptyBreak(t,e,s){const a=[...e,{type:"aderror",break:t,format:this.planFormat()}],n="overlay"===this.insertionMode?this.chainResolver(t.id):null;return n?(this.currentBreak=n,this.plan=r(n,this.insertionMode,this.selection),this.assetIndex=0,this.assetStarted=!1,"empty"===this.plan.mode?this.retireEmptyBreak(n,a,[...s,...this.noticeFor(n)]):(a.push({type:"adbreakbegin",break:n,format:this.planFormat()}),{steps:a,action:this.startAction(this.plan),noPlayableAsset:s})):(this.currentBreak=null,{steps:a,action:{kind:"end-break"},noPlayableAsset:s})}startAction(t){switch(t.mode){case"overlay-assets":return{kind:"play-asset",asset:t.assets[0],index:0,total:t.assets.length};case"overlay-backdrop":return{kind:"render-backdrop"};case"shared-single":return{kind:"play-shared",asset:t.asset}}}onOutcome(t){if(!this.currentBreak)return{steps:[],action:{kind:"await"}};const e=this.currentBreak;switch(t.kind){case"asset-started":return this.onAssetStarted(e);case"asset-ended":return this.onAssetSettled(e,!1);case"asset-errored":return this.onAssetSettled(e,!0);case"backdrop-elapsed":case"break-elapsed":return this.finalizeBreak(this.inFlightAdendPrefix(e))}}inFlightAdendPrefix(t){if(!this.assetStarted)return[];const e=this.planFormat();return"overlay-assets"===this.plan.mode?[{type:"adend",break:t,format:e,asset:this.plan.assets[this.assetIndex],adIndex:this.assetIndex,totalAds:this.plan.assets.length}]:"shared-single"===this.plan.mode?[{type:"adend",break:t,format:e,asset:this.plan.asset,adIndex:0,totalAds:1}]:[]}onAssetStarted(t){if("overlay-assets"===this.plan.mode){const e=this.plan.assets.length,s=this.plan.assets[this.assetIndex];return this.assetStarted=!0,{steps:[{type:"adbegin",break:t,format:this.planFormat(),asset:s,adIndex:this.assetIndex,totalAds:e}],action:{kind:"await"}}}return"shared-single"===this.plan.mode?(this.assetStarted=!0,{steps:[{type:"adbegin",break:t,format:this.planFormat(),asset:this.plan.asset,adIndex:0,totalAds:1}],action:{kind:"await"}}):{steps:[],action:{kind:"await"}}}onAssetSettled(t,e){if(this.assetStarted=!1,"shared-single"===this.plan.mode){const s=[],a=this.plan.asset,r=this.planFormat();return e&&s.push({type:"aderror",break:t,format:r,asset:a,adIndex:0,totalAds:1}),s.push({type:"adend",break:t,format:r,asset:a,adIndex:0,totalAds:1}),this.finalizeBreak(s)}if("overlay-assets"!==this.plan.mode)return{steps:[],action:{kind:"await"}};const s=this.plan.assets.length,a=this.plan.assets[this.assetIndex],r=[],n=this.planFormat();return e&&r.push({type:"aderror",break:t,format:n,asset:a,adIndex:this.assetIndex,totalAds:s}),r.push({type:"adend",break:t,format:n,asset:a,adIndex:this.assetIndex,totalAds:s}),this.assetIndex+=1,this.assetIndex<s?{steps:r,action:{kind:"play-asset",asset:this.plan.assets[this.assetIndex],index:this.assetIndex,total:s}}:this.finalizeBreak(r)}finalizeBreak(t,e=[]){const s=t=>e.length>0?{...t,noPlayableAsset:e}:t,a=this.currentBreak;if(!a)return s({steps:t,action:{kind:"end-break"}});const n=[...t,{type:"adbreakend",break:a,format:this.planFormat()}],i="overlay"===this.insertionMode?this.chainResolver(a.id):null;return i?(this.currentBreak=i,this.plan=r(i,this.insertionMode,this.selection),this.assetIndex=0,this.assetStarted=!1,"empty"===this.plan.mode?this.retireEmptyBreak(i,n,[...e,...this.noticeFor(i)]):(n.push({type:"adbreakbegin",break:i,format:this.planFormat()}),s({steps:n,action:this.startAction(this.plan)}))):(this.currentBreak=null,s({steps:n,action:{kind:"end-break"}}))}}
1
+ import{BreakFormat as t}from"../types/BreakManifest";import{KNOWN_BREAK_FORMATS as e,selectVariantDetailed as s,variantsOf as a}from"./selectVariant";export function selectVariant(t,a){return s(t,a??{playableFormats:e}).selected}export function resolveBreakFormat(t,e){return selectVariant(t,e)?.format}export function assetsOfVariant(e){if(!e)return[];switch(e.format){case t.SINGLE:case t.DOUBLE:case t.LSHAPE_AD:case t.LSHAPE_CONTENT:case t.OVERLAY:return e.assets;default:return[]}}export function extractAssets(t,e){return assetsOfVariant(selectVariant(t,e))}export function breakPlanEmptyReason(t,e,s={}){const a=r(t,e,s);return"empty"===a.mode?a.reason??null:null}function r(r,n,i={}){if(0===a(r).length)return{mode:"empty",reason:"no-variant",variant:null};const o=s(r,{deviceType:i.deviceType,deviceProfile:i.deviceProfile,playableFormats:"shared-element"===n?e:i.playableFormats}),d=o.selected,l=d??o.deviceQualified;if(!l)return{mode:"empty",reason:"no-qualifying-variant",variant:null};if("shared-element"===n){if(l.format===t.LSHAPE_CONTENT)return{mode:"empty",reason:"lshape-content-skipped",variant:l};const e=assetsOfVariant(l)[0];return e?{mode:"shared-single",asset:e,variant:l}:{mode:"empty",reason:"no-assets",variant:l}}if(d){if(d.format===t.LSHAPE_CONTENT)return{mode:"overlay-backdrop",variant:d};const e=assetsOfVariant(d);return e.length>0?{mode:"overlay-assets",assets:e,variant:d}:{mode:"empty",reason:"no-assets",variant:d}}if(l.format===t.LSHAPE_CONTENT)return{mode:"overlay-backdrop",variant:l};const h=assetsOfVariant(l)[0];return h?{mode:"overlay-assets",assets:[h],variant:l}:{mode:"empty",reason:"no-assets",variant:l}}export class AdBreakSequencer{constructor(t,e=()=>null,s={}){this.insertionMode=t,this.chainResolver=e,this.selection=s,this.currentBreak=null,this.plan={mode:"empty"},this.assetIndex=0,this.assetStarted=!1}planFormat(){return"variant"in this.plan?this.plan.variant?.format:void 0}beginBreak(t){if(this.currentBreak=t,this.plan=r(t,this.insertionMode,this.selection),this.assetIndex=0,this.assetStarted=!1,"empty"===this.plan.mode)return this.retireEmptyBreak(t,[],this.noticeFor(t));return{steps:[{type:"adbreakbegin",break:t,format:this.planFormat()}],action:this.startAction(this.plan)}}noticeFor(t){return"empty"===this.plan.mode&&this.plan.reason?[{breakId:t.id,reason:this.plan.reason,format:this.plan.variant?.format,declaredAssetCount:a(t).reduce((t,e)=>t+assetsOfVariant(e).length,0)}]:[]}retireEmptyBreak(t,e,s){const a=[...e,{type:"aderror",break:t,format:this.planFormat()}],n="overlay"===this.insertionMode?this.chainResolver(t.id):null;return n?(this.currentBreak=n,this.plan=r(n,this.insertionMode,this.selection),this.assetIndex=0,this.assetStarted=!1,"empty"===this.plan.mode?this.retireEmptyBreak(n,a,[...s,...this.noticeFor(n)]):(a.push({type:"adbreakbegin",break:n,format:this.planFormat()}),{steps:a,action:this.startAction(this.plan),noPlayableAsset:s})):(this.currentBreak=null,{steps:a,action:{kind:"end-break"},noPlayableAsset:s})}startAction(t){switch(t.mode){case"overlay-assets":return{kind:"play-asset",asset:t.assets[0],index:0,total:t.assets.length};case"overlay-backdrop":return{kind:"render-backdrop"};case"shared-single":return{kind:"play-shared",asset:t.asset}}}onOutcome(t){if(!this.currentBreak)return{steps:[],action:{kind:"await"}};const e=this.currentBreak;switch(t.kind){case"asset-started":return this.onAssetStarted(e);case"asset-ended":return this.onAssetSettled(e,!1);case"asset-errored":return this.onAssetSettled(e,!0);case"backdrop-elapsed":case"break-elapsed":return this.finalizeBreak(this.inFlightAdendPrefix(e))}}inFlightAdendPrefix(t){if(!this.assetStarted)return[];const e=this.planFormat();return"overlay-assets"===this.plan.mode?[{type:"adend",break:t,format:e,asset:this.plan.assets[this.assetIndex],adIndex:this.assetIndex,totalAds:this.plan.assets.length}]:"shared-single"===this.plan.mode?[{type:"adend",break:t,format:e,asset:this.plan.asset,adIndex:0,totalAds:1}]:[]}onAssetStarted(t){if("overlay-assets"===this.plan.mode){const e=this.plan.assets.length,s=this.plan.assets[this.assetIndex];return this.assetStarted=!0,{steps:[{type:"adbegin",break:t,format:this.planFormat(),asset:s,adIndex:this.assetIndex,totalAds:e}],action:{kind:"await"}}}return"shared-single"===this.plan.mode?(this.assetStarted=!0,{steps:[{type:"adbegin",break:t,format:this.planFormat(),asset:this.plan.asset,adIndex:0,totalAds:1}],action:{kind:"await"}}):{steps:[],action:{kind:"await"}}}onAssetSettled(t,e){if(this.assetStarted=!1,"shared-single"===this.plan.mode){const s=[],a=this.plan.asset,r=this.planFormat();return e&&s.push({type:"aderror",break:t,format:r,asset:a,adIndex:0,totalAds:1}),s.push({type:"adend",break:t,format:r,asset:a,adIndex:0,totalAds:1}),this.finalizeBreak(s)}if("overlay-assets"!==this.plan.mode)return{steps:[],action:{kind:"await"}};const s=this.plan.assets.length,a=this.plan.assets[this.assetIndex],r=[],n=this.planFormat();return e&&r.push({type:"aderror",break:t,format:n,asset:a,adIndex:this.assetIndex,totalAds:s}),r.push({type:"adend",break:t,format:n,asset:a,adIndex:this.assetIndex,totalAds:s}),this.assetIndex+=1,this.assetIndex<s?{steps:r,action:{kind:"play-asset",asset:this.plan.assets[this.assetIndex],index:this.assetIndex,total:s}}:this.finalizeBreak(r)}finalizeBreak(t,e=[]){const s=t=>e.length>0?{...t,noPlayableAsset:e}:t,a=this.currentBreak;if(!a)return s({steps:t,action:{kind:"end-break"}});const n=[...t,{type:"adbreakend",break:a,format:this.planFormat()}],i="overlay"===this.insertionMode?this.chainResolver(a.id):null;return i?(this.currentBreak=i,this.plan=r(i,this.insertionMode,this.selection),this.assetIndex=0,this.assetStarted=!1,"empty"===this.plan.mode?this.retireEmptyBreak(i,n,[...e,...this.noticeFor(i)]):(n.push({type:"adbreakbegin",break:i,format:this.planFormat()}),s({steps:n,action:this.startAction(this.plan)}))):(this.currentBreak=null,s({steps:n,action:{kind:"end-break"}}))}}
@@ -11,6 +11,7 @@ import { type NoPlayableAssetReason } from './AdBreakSequencer';
11
11
  import type { PauseAdResolution } from './PauseAdController';
12
12
  import { type Clock } from './BreakScheduler';
13
13
  import { PauseAdPresenter } from './adPlayer/PauseAdPresenter';
14
+ import { AssetParameterResolver } from './adPlayer/AssetParameterResolver';
14
15
  import type { BreakEndOnStreamClock } from './adPlayer/streamClockResume';
15
16
  /** Creative identity IMA reports for an ad of a GAM pod; absent for other asset kinds. */
16
17
  export interface AdCreativeIdentity {
@@ -270,6 +271,7 @@ export declare class AdPlayerController {
270
271
  * mid-break update applies from the next asset on.
271
272
  */
272
273
  updateAssetParameters(params: Record<string, string>): void;
274
+ resolveExternalVendorConfiguration(entry: Parameters<AssetParameterResolver['resolveExternalVendorConfiguration']>[0]): import("./resolveExternalVendorConfigurations").ExternalVendorConfiguration;
273
275
  updateAssetParameterMacros(macros: AssetParameterMacroUpdates): void;
274
276
  /** The live-update layer last set by {@link updateAssetParameters}; `endGamSession()` clears it. */
275
277
  get updatedAssetParameters(): Record<string, string> | undefined;
@@ -1 +1 @@
1
- import{BreakFormat as e,Timebase as t,isPostRollBreak as r}from"../types/BreakManifest";import{DEFAULT_AD_BREAK_CUT_SAFETY_MARGIN_SEC as s,DEFAULT_DOUBLE_BOX_AUDIO as a}from"../types/OptiViewAdsConfig";import{pipOverridesFormat as i,pipSuppressesBackdrop as n}from"./pictureInPicture";import{AdBreakSequencer as o,assetsOfVariant as d,resolveBreakFormat as l}from"./AdBreakSequencer";import{selectVariantDetailed as h}from"./selectVariant";import{debugLog as u}from"../diagnostics/debugLog";import{systemClock as c}from"./BreakScheduler";import{createAdPlayerState as m,invalidateMediaPreload as g}from"./adPlayer/AdPlayerState";import{PauseAdPresenter as P}from"./adPlayer/PauseAdPresenter";import{AssetParameterResolver as y}from"./adPlayer/AssetParameterResolver";import{GamPodBridge as p}from"./adPlayer/GamPodBridge";import{AdStage as A}from"./adPlayer/AdStage";import{AdPreloader as v}from"./adPlayer/AdPreloader";import{PresentationModeTracker as C}from"./adPlayer/PresentationModeTracker";import{SharedElementBreakPlayer as k}from"./adPlayer/SharedElementBreakPlayer";import{ContentResumeCoordinator as f}from"./adPlayer/ContentResumeCoordinator";import{resumeContentAfterBreak as S}from"./adPlayer/ContentRecovery";import{AssetPlayback as B}from"./adPlayer/AssetPlayback";import{BreakSequenceDriver as E}from"./adPlayer/BreakSequenceDriver";import{VariantSelector as b}from"./adPlayer/VariantSelector";import{AdPlayerEvents as F}from"./adPlayer/AdPlayerEvents";import{armPlaybackCutoff as T,clearPlaybackCutoff as M}from"./adPlayer/PlaybackCutoff";import{AdError as R}from"../types/AdError";export class AdPlayerController{get contentPaused(){return this.state.contentPaused}set contentPaused(e){this.state.contentPaused=e}get firstFrameGateActive(){return this.state.firstFrameGateActive}set firstFrameGateActive(e){this.state.firstFrameGateActive=e}get firstFrameGateShown(){return this.state.firstFrameGateShown}set firstFrameGateShown(e){this.state.firstFrameGateShown=e}get firstFrameRejector(){return this.state.firstFrameRejector}set firstFrameRejector(e){this.state.firstFrameRejector=e}get gamEventCallbacks(){return this.gamPodBridge.eventCallbacks}get vastAdManager(){return this.state.vastAdManager}set vastAdManager(e){this.state.vastAdManager=e}get currentBreak(){return this.state.currentBreak}set currentBreak(e){this.state.currentBreak=e}get currentAsset(){return this.state.currentAsset}set currentAsset(e){this.state.currentAsset=e}get callbacks(){return this.state.callbacks}set callbacks(e){this.state.callbacks=e}get isPlaying(){return this.state.isPlaying}set isPlaying(e){this.state.isPlaying=e}get effectiveBreakDurationSec(){return this.state.effectiveBreakDurationSec}set effectiveBreakDurationSec(e){this.state.effectiveBreakDurationSec=e}get adBreakCutSafetyMarginSec(){return this.state.adBreakCutSafetyMarginSec}set adBreakCutSafetyMarginSec(e){this.state.adBreakCutSafetyMarginSec=e}get durationTimer(){return this.state.durationTimer}set durationTimer(e){this.state.durationTimer=e}get adInsertionType(){return this.state.adInsertionType}set adInsertionType(e){this.state.adInsertionType=e}get breakTimebase(){return this.state.breakTimebase}set breakTimebase(e){this.state.breakTimebase=e}constructor(e,t,r,i,n=!1,o,d="parallel",l="overlay",h=s,u=a,S=!1,T=c,M="none"){this.playerContainerCreatedBySDK=!1,this.adMediaContainer=null,this.adPlayer=null,this.adContainer=null,this.companionElement=null,this.staticQuartilesFired=new Set,this.sequencer=null,this.pendingAdError=null,this.preRollHoldActive=!1,this.preRollHoldHandler=null,this.breakContentGateHandler=null,this.destroyed=!1,this.abortingBreak=!1,this.overlayImageEl=null,this.imageAssetTimer=null,this.chainResolver=null,this.transitionPhaseReporter=null,this.chaining=!1,this.diagnoseHandler=null,this.playerContainerOriginalStyle="",this.companionRemoveTimer=null,this.adFadeTimer=null,this.syncing=!1,this.contentVolumeHandler=null,this.adVolumeChangeHandler=null,this.volumeChangeCallback=null,this.stage=null,this.resizeObserver=null,this.contentVideoElement=null,this.contentVideoGeometryHandler=null,this.contentVideoMutationObserver=null,this.resumeGeneration=0,this.singleSurfaceDevice=!1,this.currentSelectedFormat=void 0,this.audioFocus=null,this.state=m(),this.state.playerContainer=r??null,this.clock=T,this.singleSurfaceDevice=S,this.contentPlayer=e,this.adBreakCutSafetyMarginSec=h,this.doubleBoxAudio=u,this.container=t,r&&(this.playerContainer=r),this.createAdAdapter=i,this.debug=n,this.state.gamConfig=o,this.preloadMode=d,this.insertionMode=l,this.pauseAdPresenter=new P({contentPlayer:this.contentPlayer,getStage:()=>this.stage,resolveUri:e=>this.resolveUri(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.assetParameters=new y(this.state,{contentPlayer:this.contentPlayer,container:this.container,getGamStreamManager:()=>this.state.gamStreamManager,getCurrentBreak:()=>this.currentBreak,getEffectiveBreakDuration:()=>this.effectiveBreakDurationSec,diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.gamPodBridge=new p(this.state,{contentPlayer:this.contentPlayer,debug:this.debug,getAdPlayer:()=>this.adPlayer,getAdContainer:()=>this.adContainer,isSharedElement:()=>"shared-element"===this.effectiveInsertionMode(),getCurrentBreak:()=>this.currentBreak,getCurrentAsset:()=>this.currentAsset,getEffectiveBreakDuration:()=>this.effectiveBreakDurationSec,getAdPlayerStreamRemainingSec:()=>this.adPlayerStreamRemainingSec(),emitStep:e=>this.emitStep(e),emitAdStart:(e,t,r,s,a)=>this.callbacks?.onAdStart(e,t,r,s,a),emitAdEnd:(e,t,r,s,a)=>this.callbacks?.onAdEnd(e,t,r,s,a),onAdEnded:()=>this.onAdEnded(),pushAssetParameters:(e,t)=>this.pushAssetParameters(e,t),resolveSessionAdTagParameters:()=>this.assetParameters.resolveSessionAdTagParameters(),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.adStage=new A({contentPlayer:this.contentPlayer,container:this.container,getPlayerContainer:()=>this.playerContainer,setPlayerContainer:e=>{this.playerContainer=e},setPlayerContainerOriginalStyle:e=>{this.playerContainerOriginalStyle=e},onPlayerContainerCreated:()=>{this.playerContainerCreatedBySDK=!0},getStage:()=>this.stage,setStage:e=>{this.stage=e},getContentVideo:()=>this.contentVideoElement,setContentVideo:e=>{this.contentVideoElement=e},getAdContainer:()=>this.adContainer,setAdContainer:e=>{this.adContainer=e},getAdMediaContainer:()=>this.adMediaContainer,setAdMediaContainer:e=>{this.adMediaContainer=e},setAdPlayer:e=>{g(this.state),this.adPlayer=e},createAdAdapter:e=>this.createAdAdapter(e),setupEventListeners:()=>this.setupEventListeners(),resizeVast:()=>this.vastAdManager?.resize(),getVariant:e=>this.getVariant(e),getCurrentBreak:()=>this.currentBreak,resolveUri:e=>this.resolveUri(e),getCompanion:()=>this.companionElement,setCompanion:e=>{this.companionElement=e},getOverlayImage:()=>this.overlayImageEl,setOverlayImage:e=>{this.overlayImageEl=e},getImageAssetTimer:()=>this.imageAssetTimer,setImageAssetTimer:e=>{this.imageAssetTimer=e},isChaining:()=>this.chaining,log:(...e)=>this.log(...e)}),this.preloader=new v({state:this.state,clock:this.clock,adStartBudgetMs:AdPlayerController.AD_START_BUDGET_MS,gamPodAdStartBudgetMs:AdPlayerController.GAM_POD_AD_START_BUDGET_MS,minAdStartBudgetMs:AdPlayerController.MIN_AD_START_BUDGET_MS,debug:this.debug,isPlaying:()=>this.isPlaying,preloadMode:this.preloadMode,effectiveInsertionMode:()=>this.effectiveInsertionMode(),getVariant:e=>this.getVariant(e),getAssets:e=>this.getAssets(e),resolveUri:e=>this.resolveUri(e),resolveAssetUri:(e,t)=>this.resolveAssetUri(e,t),getCompanionVariant:e=>this.getVariant(e),getAdPlayer:()=>this.adPlayer,getAdContainer:()=>this.adContainer,buildVastTagUrl:(e,t)=>this.buildVastTagUrl(e,t),resolveChainedSuccessor:e=>this.resolveChainedSuccessor(e),show:()=>this.show(),reapplyAdContainerLayout:e=>this.reapplyAdContainerLayout(e),getCurrentBreak:()=>this.currentBreak,onBreakVisible:e=>this.callbacks?.onBreakVisible?.(e),onAdError:e=>this.onAdError(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.presentationModes=new C(this.state,{contentPlayer:this.contentPlayer,getAdPlayer:()=>this.adPlayer,insertionMode:this.insertionMode,getCurrentBreak:()=>this.currentBreak,getCurrentFormat:()=>this.currentSelectedFormat,isSharedElementActive:()=>this.state.sharedAdClaimActive,getVariant:e=>this.getVariant(e),isAdPlaying:()=>this.isAdPlaying(),hasCurrentAsset:()=>null!==this.currentAsset,contentSourceIsReloadable:()=>null!==this.sharedElementPlayer.restorableContentSource(),adoptPictureInPictureMidBreak:()=>this.adoptPictureInPictureMidBreak(),restoreLayout:e=>this.restoreLayout(e),applyLayout:e=>this.applyLayout(e),show:()=>this.show(),playAdThroughContentElement:()=>this.sharedElementPlayer.playAdThroughContentElement(),getContentPositionAtBreakStart:()=>this.state.contentPositionAtBreakStart,setContentPositionAtBreakStart:e=>this.resumeCoordinator.reanchorMidBreak(e),gateContentForBreak:()=>this.gateContentForBreak(),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.resumeCoordinator=new f(this.state,{contentPlayer:this.contentPlayer,clock:this.clock,getInsertionMode:()=>this.effectiveInsertionMode(),gateContentForBreak:()=>this.gateContentForBreak(),clearContentGate:e=>this.clearContentGate(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.recoveryDeps={contentPlayer:e,getCallbacks:()=>this.callbacks,preloadMode:d,contentRecovery:M,resumeCoordinator:this.resumeCoordinator,diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)},this.sharedElementPlayer=new k(this.state,{contentPlayer:this.contentPlayer,getAdPlayer:()=>this.adPlayer,resolveAssetUri:(e,t)=>this.resolveAssetUri(e,t),liveEdgeDistanceSec:()=>this.resumeCoordinator.liveEdgeDistanceSec(),rebindContentElementIfSwapped:()=>this.rebindContentElementIfSwapped(),createAdAdapter:(e,t)=>this.createAdAdapter(e,t),reportAdProgress:e=>this.reportAdProgress(e),processTimedMetadata:e=>this.gamPodBridge.processTimedMetadata(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e),clearContentGate:()=>this.clearContentGate(),hide:()=>this.hide(),waitForLiveEdge:e=>this.resumeCoordinator.waitForLiveEdge(e),getVariant:e=>this.getVariant(e),getAssets:e=>this.getAssets(e)}),this.variantSelector=new b(this.state,{getEffectiveInsertionMode:()=>this.effectiveInsertionMode(),singleSurfaceDevice:this.singleSurfaceDevice,preloadMode:this.preloadMode,getIsContentPictureInPicture:()=>this.isContentPictureInPicture(),getIsGamReady:()=>this.isGamReady(),getSupportsParallelBuffering:()=>this.contentPlayer.supportsParallelBuffering,diagnose:(e,t,r)=>this.diagnose(e,t,r)}),this.assetPlayback=new B(this.state,{getAdPlayer:()=>this.adPlayer,getAdContainer:()=>this.adContainer,getAdMediaContainer:()=>this.adMediaContainer,clearStaticQuartiles:()=>this.staticQuartilesFired.clear(),getVariant:e=>this.getVariant(e),getGamEventCallbacks:()=>this.gamEventCallbacks,getSequencer:()=>this.sequencer,debug:this.debug,resolveUri:e=>this.resolveUri(e),buildGamUrl:(e,t)=>this.buildGamUrl(e,t),buildVastTagUrl:(e,t)=>this.buildVastTagUrl(e,t),onAdError:e=>this.onAdError(e),onAdEnded:()=>this.onAdEnded(),drive:e=>this.drive(e),clearOverlayImage:()=>this.clearOverlayImage(),revealFirstFrame:()=>this.preloader.revealFirstFrame(),transferPictureInPictureToAd:()=>this.presentationModes.transferPictureInPictureToAd(),isGamPodAsset:e=>this.isGamPodAsset(e),hasGamIdentityMismatch:e=>this.gamPodBridge.hasIdentityMismatch(e),beginGamPodTracking:e=>this.gamPodBridge.beginGamPodTracking(e),recordAdProgress:e=>this.adPlayerEvents.recordAdProgress(e),reportPhase:e=>this.reportPhase(e),armAdStartBudget:e=>this.armAdStartBudget(e),remainingAdStartBudgetMs:()=>this.remainingAdStartBudgetMs(),loadWithinBudget:(e,t)=>this.loadWithinBudget(e,t),waitForFirstFrame:()=>this.waitForFirstFrame(),getOverlayImage:()=>this.overlayImageEl,setOverlayImage:e=>{this.overlayImageEl=e},getImageAssetTimer:()=>this.imageAssetTimer,setImageAssetTimer:e=>{this.imageAssetTimer=e},getVastPodPosition:()=>this.vastPodPosition,setVastPodPosition:e=>{this.vastPodPosition=e},diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.breakSequenceDriver=new E(this.state,{getChainResolver:()=>this.chainResolver,getEffectiveInsertionMode:()=>this.effectiveInsertionMode(),getVastPodPosition:()=>this.vastPodPosition,setVastPodPosition:e=>{this.vastPodPosition=e},getPendingAdError:()=>this.pendingAdError,setPendingAdError:e=>{this.pendingAdError=e},getChaining:()=>this.chaining,setChaining:e=>{this.chaining=e},isExpandingPodAsset:e=>this.isExpandingPodAsset(e),fallBackToPodLevelReporting:()=>this.fallBackToPodLevelReporting(),resetGamPodTracking:()=>this.resetGamPodTracking(),emitGamPodSteps:e=>this.gamPodBridge.emitGamPodSteps(e),playAsset:(e,t,r)=>this.playAsset(e,t,r),endBreak:()=>this.endBreak(),playBreak:(e,t,r)=>this.playBreak(e,t,r),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.adPlayerEvents=new F(this.state,{getAdPlayer:()=>this.adPlayer,getContentPlayer:()=>this.contentPlayer,getGamEventCallbacks:()=>this.gamEventCallbacks,getSequencer:()=>this.sequencer,getAudioFocus:()=>this.audioFocus,getSyncing:()=>this.syncing,setSyncing:e=>{this.syncing=e},setAdVolumeChangeHandler:e=>{this.adVolumeChangeHandler=e},setContentVolumeHandler:e=>{this.contentVolumeHandler=e},notifyVolumeChange:()=>this.notifyVolumeChange(),onAdEnded:()=>this.onAdEnded(),processTimedMetadata:e=>this.gamPodBridge.processTimedMetadata(e),toAdError:e=>this.toAdError(e),revealFirstFrame:()=>this.revealFirstFrame(),clearFirstFrameResolver:()=>this.preloader.clearFirstFrameResolver(),drive:e=>this.drive(e),setPendingAdError:e=>{this.pendingAdError=e},log:(...e)=>this.log(...e),maybePrepositionContentForResume:()=>"single-decoder"!==this.preloadMode&&this.resumeCoordinator.maybePrepositionContentForResume(),maybeCatchUpContentForResume:e=>"single-decoder"!==this.preloadMode&&this.resumeCoordinator.maybeCatchUpContentForResume(e),getStaticQuartilesFired:()=>this.staticQuartilesFired,onGamPodAdProgress:e=>this.gamPodBridge.onGamPodAdProgress(e)})}setGamEventCallbacks(e){this.gamPodBridge.setEventCallbacks(e)}setDiagnoseHandler(e){this.diagnoseHandler=e}diagnose(e,t,r){this.diagnoseHandler?.(e,t,r)}holdContentForPreRoll(e){if(this.preRollHoldActive)return;const t=this.getVariant(e);t&&this.shouldPauseContent(t.format)&&(this.preRollHoldActive=!0,this.contentPlayer.pause(),this.preRollHoldHandler=()=>{this.preRollHoldActive&&this.contentPlayer.pause()},this.contentPlayer.on("playing",this.preRollHoldHandler),this.diagnose("DA-PREROLL-CONTENT-HELD","Content held at session start until the pending pre-roll begins.",{breakId:e.id}))}releaseContentHold(){this.preRollHoldActive&&(this.preRollHoldActive=!1,this.preRollHoldHandler&&(this.contentPlayer.off("playing",this.preRollHoldHandler),this.preRollHoldHandler=null))}gateContentForBreak(){this.contentPlayer.pause(),this.breakContentGateHandler||(this.breakContentGateHandler=()=>{this.contentPaused&&!this.state.resumeCatchupActive&&this.contentPlayer.pause()},this.contentPlayer.on("playing",this.breakContentGateHandler))}clearContentGate(e=!1){this.resumeCoordinator.endResumeCatchup(e),this.breakContentGateHandler&&(this.contentPlayer.off("playing",this.breakContentGateHandler),this.breakContentGateHandler=null)}setChainResolver(e){this.chainResolver=e}setResumeCueAnchorResolver(e){this.resumeCoordinator.setCueAnchorResolver(e)}setResumeCueEndResolver(e){this.resumeCoordinator.setCueEndResolver(e)}ingestStreamClockCue(e){this.resumeCoordinator.ingestStreamClockCue(e)}setTransitionPhaseReporter(e){this.transitionPhaseReporter=e}reportPhase(e){this.transitionPhaseReporter?.(e)}setBreakResumePolicy(e,t,r=!1){this.adInsertionType=e,this.breakTimebase=t,this.state.continueContentDuringBreak=r,this.state.continueRefusalReported=!1}initialize(){this.adContainer||(this.setupOverlay(),this.presentationModes.setupPictureInPictureTracking(),"adaptive"===this.insertionMode&&this.presentationModes.setupFullscreenTracking())}async startGamSession(e,t){await this.gamPodBridge.startGamSession(e,t)}endGamSession(){this.gamPodBridge.endGamSession()}setSessionAssetParameters(e){this.assetParameters.setSessionAssetParameters(e)}setManifestAssetParameters(e){this.assetParameters.setManifestAssetParameters(e)}updateAssetParameters(e){this.assetParameters.updateAssetParameters(e)}updateAssetParameterMacros(e){this.assetParameters.updateAssetParameterMacros(e)}get updatedAssetParameters(){return this.state.updatedAssetParameters}setSessionAssetParameterMacros(e){this.assetParameters.setSessionAssetParameterMacros(e)}get sessionAssetParameterMacros(){return this.assetParameters.getSessionAssetParameterMacros()}buildVastTagUrl(e,t){return this.assetParameters.buildVastTagUrl(e,t)}pushAssetParameters(e,t){this.assetParameters.pushAssetParameters(e,t)}setupOverlay(){this.adStage.setupOverlay()}isGamPodAsset(e){return this.gamPodBridge.isGamPodAsset(e)}isExpandingPodAsset(e){return this.gamPodBridge.isExpandingPodAsset(e)}fallBackToPodLevelReporting(){this.gamPodBridge.fallBackToPodLevelReporting()}resetGamPodTracking(){this.gamPodBridge.resetGamPodTracking()}emitGamPodSteps(e){this.gamPodBridge.emitGamPodSteps(e)}isGamEnabled(){return this.gamPodBridge.isGamEnabled()}isGamReady(){return this.gamPodBridge.isGamReady()}isOverlayInsertion(){return"overlay"===this.effectiveInsertionMode()}settleAssetProgress(){this.adPlayerEvents.settleAssetProgress()}reportAdProgress(e){this.adPlayerEvents.reportAdProgress(e)}setupEventListeners(){this.adPlayerEvents.setupEventListeners()}async preload(e){return this.preloader.preload(e)}renderLshapeContentBackdrop(e){this.adStage.renderLshapeContentBackdrop(e)}currentInsertionMode(){return this.presentationModes.currentInsertionMode()}effectiveInsertionMode(){return this.presentationModes.effectiveInsertionMode()}isContentPictureInPicture(){return this.presentationModes.isPictureInPicture()}rebindContentElementIfSwapped(){this.presentationModes.rebindContentElementIfSwapped()}teardownFullscreenTracking(){this.presentationModes.teardownFullscreenTracking()}teardownPictureInPictureTracking(){this.presentationModes.teardownPictureInPictureTracking()}isPictureInPicture(){return this.presentationModes.isPictureInPicture()}pictureInPictureOwner(){return this.presentationModes.pictureInPictureOwner()}isShowingAd(){if(!this.isAdPlaying())return!1;const e=this.currentDeclaredFormat();return!n(e,this.isContentPictureInPicture())}currentDeclaredFormat(){return this.currentSelectedFormat??(this.currentBreak?l(this.currentBreak):void 0)}async playBreak(t,s,a){if(this.state.preloadGeneration++,this.resumeGeneration++,!this.sharedElementPlayer.beginSharedActivity())return;this.releaseContentHold(),this.rebindContentElementIfSwapped();const n=a?.effectiveDurationSec??null;this.effectiveBreakDurationSec=null!==n&&n>0?n:null;const d=this.effectiveBreakDurationSec??t.duration;if("shared-element"===this.effectiveInsertionMode())return g(this.state),void await this.sharedElementPlayer.playSharedElementBreak(t,s);if(!this.adPlayer)return void this.log("playBreak called before initialize()");const l=this.getVariant(t);if(!l)return void this.log("No valid variant found for break:",t.id);this.currentBreak=t,this.callbacks=s,this.isPlaying=!0,this.firstFrameGateActive=a?.firstFrameGate??!1,this.firstFrameGateShown=!1;const h=this.continueContentDuringBreakReason(l.format),u=r(t),c=this.shouldPauseContent(l.format)&&"ok"===h&&!u;c||u||this.state.continueRefusalReported||!this.shouldPauseContent(l.format)||(this.state.continueRefusalReported=!0,this.diagnose("DA-CONTINUE-PLAYOUT-REFUSED",`Content will be paused for breaks this session: ${h}`,{reason:h,format:l.format})),this.audioFocus=l.format===e.DOUBLE?this.doubleBoxAudio:c?"ad":null,this.adPlayer&&("content"===this.audioFocus?(this.adPlayer.muted=!0,this.adPlayer.volume=0):(this.adPlayer.muted=this.contentPlayer.muted,this.adPlayer.volume=this.contentPlayer.volume,"ad"===this.audioFocus&&(this.contentPlayer.muted=!0)));const m=this.declaredFormatOf(t);if(this.currentSelectedFormat=m,this.state.pipAdoptedForBreak=i(m,this.isContentPictureInPicture()),this.state.pipAdoptedForBreak&&this.diagnose("DA-PIP-FORMAT-OVERRIDE",`Picture-in-picture: ${m} break plays as single`,{declared:m,effective:e.SINGLE,reason:"picture-in-picture",midBreak:!1}),this.shouldPauseContent(l.format)?(this.resumeCoordinator.captureBreakAnchor(t),c?(this.contentPaused=!1,this.resumeCoordinator.beginContinueContentPlayout()):(this.contentPaused=!0,this.gateContentForBreak())):this.contentPaused=!1,this.applyLayout(l),l.format===e.LSHAPE_CONTENT)return this.renderLshapeContentBackdrop(l),void(d&&d>0?(this.log("Starting duration timer:",d,"seconds"),this.durationTimer=setTimeout(()=>{this.log("Duration timer expired, ending break"),this.endBreak()},1e3*d)):this.endBreak());this.firstFrameGateActive||(this.show(),this.reapplyAdContainerLayout(l));if(0===this.getAssets(t).length)return this.log("No assets in break, ending immediately"),void this.endBreak();{const e=Math.max(0,d||0)+this.adBreakCutSafetyMarginSec;T(this.state,e,()=>{this.log("Break-cut timer expired, ending break"),this.firstFrameRejector?this.onAdError(new R("Break cut before first frame rendered","DA-AD-START-TIMEOUT")):this.sequencer&&this.currentBreak&&this.isPlaying?(this.callbacks?.onBreakCut?.(this.currentBreak),this.drive(this.sequencer.onOutcome({kind:"break-elapsed"}))):this.endBreak()},()=>this.onAdError(new R("Ad playback startup timed out","DA-AD-START-TIMEOUT")))}this.sequencer=new o("overlay",()=>null,this.selectionInputs()),await this.drive(this.sequencer.beginBreak(t)),this.preloadChainedSuccessor(t.id)}get resumeHandoverInMotion(){return this.state.resumeCatchupActive}reapplyAdContainerLayout(e){this.adStage.reapplyAdContainerLayout(e)}adoptPictureInPictureMidBreak(){this.presentationModes.adoptPictureInPictureMidBreak()}async restorePictureInPictureToContent(){await this.presentationModes.restorePictureInPictureToContent()}continueContentDuringBreakReason(e){return this.variantSelector.continueContentDuringBreakReason(e)}shouldPauseContent(t){return t===e.SINGLE||t===e.LSHAPE_AD}selectionInputs(){return this.variantSelector.selectionInputs()}breakNothingToPlayReason(e){return this.variantSelector.breakNothingToPlayReason(e)}unknownVariantFormatsOf(e){return this.variantSelector.unknownVariantFormatsOf(e)}diagnoseUnknownVariantFormats(e){this.variantSelector.diagnoseUnknownVariantFormats(e)}declaredFormatOf(e){const{selected:t,deviceQualified:r}=h(e,this.selectionInputs());return(t??r)?.format??l(e)}getVariant(e){return this.variantSelector.getVariant(e)}applyLayout(e){this.adStage.applyLayout(e)}restoreLayout(e){this.adStage.restoreLayout(e)}getAssets(e){return d(this.getVariant(e))}async playAsset(e,t,r){return this.assetPlayback.playAsset(e,t,r)}clearOverlayImage(){this.adStage.clearOverlayImage()}async showPauseImage(e){return this.pauseAdPresenter.showPauseImage(e)}hidePauseImage(){this.pauseAdPresenter.hidePauseImage()}async drive(e){return this.breakSequenceDriver.drive(e)}emitStep(e){this.breakSequenceDriver.emitStep(e)}async resolveAssetUri(e,t){return this.assetPlayback.resolveAssetUri(e,t)}async buildGamUrl(e,t){return this.gamPodBridge.buildGamUrl(e,t)}resolveUri(e){return this.assetParameters.resolveUri(e)}adPlayerStreamRemainingSec(){return this.assetPlayback.adPlayerStreamRemainingSec()}onAdEnded(){this.currentBreak&&this.isPlaying&&this.sequencer&&(this.settleAssetProgress(),this.drive(this.sequencer.onOutcome({kind:"asset-ended"})))}toAdError(e){return this.assetPlayback.toAdError(e)}onAdError(e){this.adPlayerEvents.onAdError(e)}endBreak(){if(!this.currentBreak)return;this.log("Break ended:",this.currentBreak.id),M(this.state),this.state.gamPodTracker&&this.emitGamPodSteps(this.state.gamPodTracker.finish()),this.resetGamPodTracking(),this.pushAssetParameters(void 0);const e=this.currentBreak,s=this.getVariant(e)?.format;let a=this.abortingBreak?null:this.resolveChainedSuccessor(e.id);if(a){const e=this.breakNothingToPlayReason(a);this.diagnoseUnknownVariantFormats(a),e&&(this.diagnose("DA-BREAK-NO-PLAYABLE-ASSET",`chained break ${a.id} has no playable variant (${e}); it will not begin.`,{breakId:a.id,reason:e}),this.callbacks?.onAdError(a,void 0,new R(`Break ${a.id} has no playable variant (${e})`,"DA-BREAK-NO-PLAYABLE-ASSET")),this.callbacks?.onChainedBreakSkipped?.(a),a=null)}if(a)return void this.advanceToChainedBreak(e,a);if(this.currentSelectedFormat=void 0,this.resumeCoordinator.endContinueContentPlayout(),this.restorePictureInPictureToContent(),this.isPlaying=!1,this.currentBreak=null,this.resumeGeneration++,this.effectiveBreakDurationSec=null,g(this.state),this.preloader.clearWarmedBreaks(),this.firstFrameGateActive=!1,this.firstFrameGateShown=!1,this.clearFirstFrame("Break ended before first frame"),"ad"===this.audioFocus&&this.adPlayer?(this.contentPlayer.muted=this.adPlayer.muted,this.contentPlayer.volume=this.adPlayer.volume):"content"===this.audioFocus&&this.adPlayer&&(this.adPlayer.muted=this.contentPlayer.muted,this.adPlayer.volume=this.contentPlayer.volume),this.audioFocus=null,this.clearOverlayImage(),this.vastAdManager?.reset(),this.hide(),this.restoreLayout(s),this.adPlayer?.pause(),this.state.sharedAdClaimActive){const t=this.callbacks;return this.sharedElementPlayer.detachSharedAdListeners(),this.abortingBreak=!1,this.state.earlyReturnResumeOffsetSec=null,this.sharedElementPlayer.restoreSharedElementContent(e),void t?.onBreakEnd(e)}const i="recreate"===this.recoveryDeps.contentRecovery&&"function"==typeof this.contentPlayer.recreateMediaPipeline,n="single-decoder"===this.preloadMode||i?this.adPlayer?.unload?.():void 0;if(this.contentPaused&&r(e))this.contentPaused=!1,this.clearContentGate();else if(this.contentPaused){this.contentPaused=!1,this.clearContentGate(this.resumeHandoverInMotion);const r=this.resumeGeneration;S(this.recoveryDeps,{breakInfo:e,earlyReturnOffsetSec:this.state.earlyReturnResumeOffsetSec,isLiveResume:this.breakTimebase===t.WALLCLOCK,released:n,isCurrent:()=>r===this.resumeGeneration})}this.abortingBreak=!1,this.state.earlyReturnResumeOffsetSec=null,this.callbacks?.onBreakEnd(e)}currentAdAsset(){return this.isPlaying?this.currentAsset:null}skipBreak(){this.isPlaying&&(this.log("Skipping break:",this.currentBreak?.id),M(this.state),this.sequencer&&this.currentBreak?this.drive(this.sequencer.onOutcome({kind:"break-elapsed"})):this.endBreak())}abortBreak(e){this.isPlaying&&(this.log("Early return — break removed from manifest:",this.currentBreak?.id),this.state.earlyReturnResumeOffsetSec=Math.max(0,e),this.abortingBreak=!0,M(this.state),this.sequencer&&this.currentBreak?this.drive(this.sequencer.onOutcome({kind:"break-elapsed"})):this.endBreak())}stopActiveBreak(){g(this.state),this.sharedElementPlayer.cancelSharedRestore()&&this.isPlaying&&(this.log("Aborting active break on session end:",this.currentBreak?.id),M(this.state),this.sharedElementPlayer.detachSharedAdListeners(),this.sharedElementPlayer.releaseContentElementAdPlayer(),this.adPlayer?.pause(),this.clearOverlayImage(),this.vastAdManager?.reset(),this.hide(),this.restoreLayout(this.currentBreak?this.getVariant(this.currentBreak)?.format??void 0:void 0),this.isPlaying=!1,this.currentBreak=null,this.currentAsset=null,this.contentPaused=!1,this.clearContentGate(),this.resumeCoordinator.endContinueContentPlayout(),this.effectiveBreakDurationSec=null,this.firstFrameGateActive=!1,this.firstFrameGateShown=!1,this.clearFirstFrame("Break aborted before first frame"),this.audioFocus=null)}resolveChainedSuccessor(e){return this.breakSequenceDriver.resolveChainedSuccessor(e)}advanceToChainedBreak(e,t){this.breakSequenceDriver.advanceToChainedBreak(e,t)}preloadChainedSuccessor(e){this.preloader.preloadChainedSuccessor(e)}revealFirstFrame(){this.assetPlayback.revealFirstFrame()}armAdStartBudget(e){this.preloader.armAdStartBudget(e)}remainingAdStartBudgetMs(){return this.preloader.remainingAdStartBudgetMs()}loadWithinBudget(e,t){return this.preloader.loadWithinBudget(e,t)}async waitForFirstFrame(){return this.preloader.waitForFirstFrame()}clearFirstFrame(e="Break ended before first frame"){this.preloader.clearFirstFrame(e)}show(){this.adStage.show()}hide(){this.adStage.hide()}isAdPlaying(){return this.isPlaying}get muted(){return"content"===this.audioFocus?this.contentPlayer.muted:"ad"===this.audioFocus?this.adPlayer?this.adPlayer.muted:this.contentPlayer.muted:this.isPlaying&&this.adPlayer?this.adPlayer.muted:this.contentPlayer.muted}set muted(e){if("content"===this.audioFocus)this.contentPlayer.muted=e;else if("ad"===this.audioFocus)this.adPlayer&&(this.adPlayer.muted=e);else{(this.isPlaying&&this.adPlayer?this.adPlayer:this.contentPlayer).muted=e}this.vastAdManager?.setMuted(e),this.notifyVolumeChange()}get volume(){return"content"===this.audioFocus?this.contentPlayer.volume:"ad"===this.audioFocus?this.adPlayer?this.adPlayer.volume:this.contentPlayer.volume:this.isPlaying&&this.adPlayer?this.adPlayer.volume:this.contentPlayer.volume}set volume(e){if("content"===this.audioFocus)this.contentPlayer.volume=e;else if("ad"===this.audioFocus)this.adPlayer&&(this.adPlayer.volume=e);else{(this.isPlaying&&this.adPlayer?this.adPlayer:this.contentPlayer).volume=e}this.vastAdManager?.setVolume(e),this.notifyVolumeChange()}setVolumeChangeCallback(e){this.volumeChangeCallback=e}notifyVolumeChange(){this.volumeChangeCallback?.(this.muted,this.volume)}destroy(){if(this.destroyed)return;if(this.resumeGeneration++,g(this.state),!this.sharedElementPlayer.beginSharedActivity())return;this.destroyed=!0,this.adStage.destroy(),this.resumeCoordinator.cancelResumeLandedProbe(),this.resumeCoordinator.dispose(),this.resumeCoordinator.endResumeCatchup(),this.resumeCoordinator.endContinueContentPlayout(),this.state.resumePrepositionSettle&&(clearTimeout(this.state.resumePrepositionSettle),this.state.resumePrepositionSettle=null),this.releaseContentHold(),this.clearContentGate(),this.clearFirstFrame("Controller destroyed before first frame"),this.firstFrameGateActive=!1,this.firstFrameGateShown=!1,this.resetGamPodTracking(),M(this.state),this.companionRemoveTimer&&(clearTimeout(this.companionRemoveTimer),this.companionRemoveTimer=null),this.adFadeTimer&&(clearTimeout(this.adFadeTimer),this.adFadeTimer=null),this.adPlayer?.pause(),this.clearOverlayImage(),this.pauseAdPresenter.destroy(),this.contentVolumeHandler&&(this.contentPlayer.off("volumechange",this.contentVolumeHandler),this.contentVolumeHandler=null),this.sharedElementPlayer.detachSharedAdListeners(),this.sharedElementPlayer.releaseContentElementAdPlayer(),this.state.pipTransferredToAd=!1,this.teardownFullscreenTracking(),this.teardownPictureInPictureTracking(),this.adVolumeChangeHandler&&this.adPlayer&&this.adPlayer.off("volumechange",this.adVolumeChangeHandler),this.adVolumeChangeHandler=null,this.hide(),this.adStage.destroy(),this.resizeObserver?.disconnect(),this.resizeObserver=null,this.contentVideoMutationObserver?.disconnect(),this.contentVideoMutationObserver=null,this.contentVideoElement&&this.contentVideoGeometryHandler&&(this.contentVideoElement.removeEventListener("loadedmetadata",this.contentVideoGeometryHandler),this.contentVideoElement.removeEventListener("resize",this.contentVideoGeometryHandler)),this.contentVideoElement=null,this.contentVideoGeometryHandler=null;const e=this.adStage.restoreContent(this.playerContainerCreatedBySDK,this.playerContainerOriginalStyle);this.companionElement&&this.companionElement.parentElement&&(this.companionElement.parentElement.removeChild(this.companionElement),this.companionElement=null),this.isPlaying=!1,this.currentBreak=null,this.adContainer&&this.adContainer.parentElement&&this.adContainer.parentElement.removeChild(this.adContainer),!e&&this.stage&&this.stage.parentElement&&this.stage.parentElement.removeChild(this.stage),this.stage=null,this.adContainer=null,this.adMediaContainer=null;try{this.adPlayer?.destroy()}catch(e){this.log("Ad player adapter destroy failed (ignored):",e)}this.adPlayer=null,this.callbacks=null,this.gamPodBridge.destroy(),this.vastAdManager?.destroy(),this.vastAdManager=null,this.log("Ad player destroyed")}log(...e){this.debug&&u("[OptiViewAds:AdPlayerController]",...e)}}AdPlayerController.AD_START_BUDGET_MS=5e3,AdPlayerController.GAM_POD_AD_START_BUDGET_MS=1e4,AdPlayerController.MIN_AD_START_BUDGET_MS=3e3;
1
+ import{BreakFormat as e,Timebase as t,isPostRollBreak as r}from"../types/BreakManifest";import{DEFAULT_AD_BREAK_CUT_SAFETY_MARGIN_SEC as s,DEFAULT_DOUBLE_BOX_AUDIO as a}from"../types/OptiViewAdsConfig";import{pipOverridesFormat as i,pipSuppressesBackdrop as n}from"./pictureInPicture";import{AdBreakSequencer as o,assetsOfVariant as d,resolveBreakFormat as l}from"./AdBreakSequencer";import{selectVariantDetailed as h}from"./selectVariant";import{debugLog as u}from"../diagnostics/debugLog";import{systemClock as c}from"./BreakScheduler";import{createAdPlayerState as m,invalidateMediaPreload as g}from"./adPlayer/AdPlayerState";import{PauseAdPresenter as P}from"./adPlayer/PauseAdPresenter";import{AssetParameterResolver as y}from"./adPlayer/AssetParameterResolver";import{GamPodBridge as p}from"./adPlayer/GamPodBridge";import{AdStage as A}from"./adPlayer/AdStage";import{AdPreloader as v}from"./adPlayer/AdPreloader";import{PresentationModeTracker as C}from"./adPlayer/PresentationModeTracker";import{SharedElementBreakPlayer as k}from"./adPlayer/SharedElementBreakPlayer";import{ContentResumeCoordinator as f}from"./adPlayer/ContentResumeCoordinator";import{resumeContentAfterBreak as S}from"./adPlayer/ContentRecovery";import{AssetPlayback as B}from"./adPlayer/AssetPlayback";import{BreakSequenceDriver as E}from"./adPlayer/BreakSequenceDriver";import{VariantSelector as b}from"./adPlayer/VariantSelector";import{AdPlayerEvents as F}from"./adPlayer/AdPlayerEvents";import{armPlaybackCutoff as T,clearPlaybackCutoff as M}from"./adPlayer/PlaybackCutoff";import{AdError as R}from"../types/AdError";export class AdPlayerController{get contentPaused(){return this.state.contentPaused}set contentPaused(e){this.state.contentPaused=e}get firstFrameGateActive(){return this.state.firstFrameGateActive}set firstFrameGateActive(e){this.state.firstFrameGateActive=e}get firstFrameGateShown(){return this.state.firstFrameGateShown}set firstFrameGateShown(e){this.state.firstFrameGateShown=e}get firstFrameRejector(){return this.state.firstFrameRejector}set firstFrameRejector(e){this.state.firstFrameRejector=e}get gamEventCallbacks(){return this.gamPodBridge.eventCallbacks}get vastAdManager(){return this.state.vastAdManager}set vastAdManager(e){this.state.vastAdManager=e}get currentBreak(){return this.state.currentBreak}set currentBreak(e){this.state.currentBreak=e}get currentAsset(){return this.state.currentAsset}set currentAsset(e){this.state.currentAsset=e}get callbacks(){return this.state.callbacks}set callbacks(e){this.state.callbacks=e}get isPlaying(){return this.state.isPlaying}set isPlaying(e){this.state.isPlaying=e}get effectiveBreakDurationSec(){return this.state.effectiveBreakDurationSec}set effectiveBreakDurationSec(e){this.state.effectiveBreakDurationSec=e}get adBreakCutSafetyMarginSec(){return this.state.adBreakCutSafetyMarginSec}set adBreakCutSafetyMarginSec(e){this.state.adBreakCutSafetyMarginSec=e}get durationTimer(){return this.state.durationTimer}set durationTimer(e){this.state.durationTimer=e}get adInsertionType(){return this.state.adInsertionType}set adInsertionType(e){this.state.adInsertionType=e}get breakTimebase(){return this.state.breakTimebase}set breakTimebase(e){this.state.breakTimebase=e}constructor(e,t,r,i,n=!1,o,d="parallel",l="overlay",h=s,u=a,S=!1,T=c,M="none"){this.playerContainerCreatedBySDK=!1,this.adMediaContainer=null,this.adPlayer=null,this.adContainer=null,this.companionElement=null,this.staticQuartilesFired=new Set,this.sequencer=null,this.pendingAdError=null,this.preRollHoldActive=!1,this.preRollHoldHandler=null,this.breakContentGateHandler=null,this.destroyed=!1,this.abortingBreak=!1,this.overlayImageEl=null,this.imageAssetTimer=null,this.chainResolver=null,this.transitionPhaseReporter=null,this.chaining=!1,this.diagnoseHandler=null,this.playerContainerOriginalStyle="",this.companionRemoveTimer=null,this.adFadeTimer=null,this.syncing=!1,this.contentVolumeHandler=null,this.adVolumeChangeHandler=null,this.volumeChangeCallback=null,this.stage=null,this.resizeObserver=null,this.contentVideoElement=null,this.contentVideoGeometryHandler=null,this.contentVideoMutationObserver=null,this.resumeGeneration=0,this.singleSurfaceDevice=!1,this.currentSelectedFormat=void 0,this.audioFocus=null,this.state=m(),this.state.playerContainer=r??null,this.clock=T,this.singleSurfaceDevice=S,this.contentPlayer=e,this.adBreakCutSafetyMarginSec=h,this.doubleBoxAudio=u,this.container=t,r&&(this.playerContainer=r),this.createAdAdapter=i,this.debug=n,this.state.gamConfig=o,this.preloadMode=d,this.insertionMode=l,this.pauseAdPresenter=new P({contentPlayer:this.contentPlayer,getStage:()=>this.stage,resolveUri:e=>this.resolveUri(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.assetParameters=new y(this.state,{contentPlayer:this.contentPlayer,container:this.container,getGamStreamManager:()=>this.state.gamStreamManager,getCurrentBreak:()=>this.currentBreak,getEffectiveBreakDuration:()=>this.effectiveBreakDurationSec,diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.gamPodBridge=new p(this.state,{contentPlayer:this.contentPlayer,debug:this.debug,getAdPlayer:()=>this.adPlayer,getAdContainer:()=>this.adContainer,isSharedElement:()=>"shared-element"===this.effectiveInsertionMode(),getCurrentBreak:()=>this.currentBreak,getCurrentAsset:()=>this.currentAsset,getEffectiveBreakDuration:()=>this.effectiveBreakDurationSec,getAdPlayerStreamRemainingSec:()=>this.adPlayerStreamRemainingSec(),emitStep:e=>this.emitStep(e),emitAdStart:(e,t,r,s,a)=>this.callbacks?.onAdStart(e,t,r,s,a),emitAdEnd:(e,t,r,s,a)=>this.callbacks?.onAdEnd(e,t,r,s,a),onAdEnded:()=>this.onAdEnded(),pushAssetParameters:(e,t)=>this.pushAssetParameters(e,t),resolveSessionAdTagParameters:()=>this.assetParameters.resolveSessionAdTagParameters(),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.adStage=new A({contentPlayer:this.contentPlayer,container:this.container,getPlayerContainer:()=>this.playerContainer,setPlayerContainer:e=>{this.playerContainer=e},setPlayerContainerOriginalStyle:e=>{this.playerContainerOriginalStyle=e},onPlayerContainerCreated:()=>{this.playerContainerCreatedBySDK=!0},getStage:()=>this.stage,setStage:e=>{this.stage=e},getContentVideo:()=>this.contentVideoElement,setContentVideo:e=>{this.contentVideoElement=e},getAdContainer:()=>this.adContainer,setAdContainer:e=>{this.adContainer=e},getAdMediaContainer:()=>this.adMediaContainer,setAdMediaContainer:e=>{this.adMediaContainer=e},setAdPlayer:e=>{g(this.state),this.adPlayer=e},createAdAdapter:e=>this.createAdAdapter(e),setupEventListeners:()=>this.setupEventListeners(),resizeVast:()=>this.vastAdManager?.resize(),getVariant:e=>this.getVariant(e),getCurrentBreak:()=>this.currentBreak,resolveUri:e=>this.resolveUri(e),getCompanion:()=>this.companionElement,setCompanion:e=>{this.companionElement=e},getOverlayImage:()=>this.overlayImageEl,setOverlayImage:e=>{this.overlayImageEl=e},getImageAssetTimer:()=>this.imageAssetTimer,setImageAssetTimer:e=>{this.imageAssetTimer=e},isChaining:()=>this.chaining,log:(...e)=>this.log(...e)}),this.preloader=new v({state:this.state,clock:this.clock,adStartBudgetMs:AdPlayerController.AD_START_BUDGET_MS,gamPodAdStartBudgetMs:AdPlayerController.GAM_POD_AD_START_BUDGET_MS,minAdStartBudgetMs:AdPlayerController.MIN_AD_START_BUDGET_MS,debug:this.debug,isPlaying:()=>this.isPlaying,preloadMode:this.preloadMode,effectiveInsertionMode:()=>this.effectiveInsertionMode(),getVariant:e=>this.getVariant(e),getAssets:e=>this.getAssets(e),resolveUri:e=>this.resolveUri(e),resolveAssetUri:(e,t)=>this.resolveAssetUri(e,t),getCompanionVariant:e=>this.getVariant(e),getAdPlayer:()=>this.adPlayer,getAdContainer:()=>this.adContainer,buildVastTagUrl:(e,t)=>this.buildVastTagUrl(e,t),resolveChainedSuccessor:e=>this.resolveChainedSuccessor(e),show:()=>this.show(),reapplyAdContainerLayout:e=>this.reapplyAdContainerLayout(e),getCurrentBreak:()=>this.currentBreak,onBreakVisible:e=>this.callbacks?.onBreakVisible?.(e),onAdError:e=>this.onAdError(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.presentationModes=new C(this.state,{contentPlayer:this.contentPlayer,getAdPlayer:()=>this.adPlayer,insertionMode:this.insertionMode,getCurrentBreak:()=>this.currentBreak,getCurrentFormat:()=>this.currentSelectedFormat,isSharedElementActive:()=>this.state.sharedAdClaimActive,getVariant:e=>this.getVariant(e),isAdPlaying:()=>this.isAdPlaying(),hasCurrentAsset:()=>null!==this.currentAsset,contentSourceIsReloadable:()=>null!==this.sharedElementPlayer.restorableContentSource(),adoptPictureInPictureMidBreak:()=>this.adoptPictureInPictureMidBreak(),restoreLayout:e=>this.restoreLayout(e),applyLayout:e=>this.applyLayout(e),show:()=>this.show(),playAdThroughContentElement:()=>this.sharedElementPlayer.playAdThroughContentElement(),getContentPositionAtBreakStart:()=>this.state.contentPositionAtBreakStart,setContentPositionAtBreakStart:e=>this.resumeCoordinator.reanchorMidBreak(e),gateContentForBreak:()=>this.gateContentForBreak(),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.resumeCoordinator=new f(this.state,{contentPlayer:this.contentPlayer,clock:this.clock,getInsertionMode:()=>this.effectiveInsertionMode(),gateContentForBreak:()=>this.gateContentForBreak(),clearContentGate:e=>this.clearContentGate(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.recoveryDeps={contentPlayer:e,getCallbacks:()=>this.callbacks,preloadMode:d,contentRecovery:M,resumeCoordinator:this.resumeCoordinator,diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)},this.sharedElementPlayer=new k(this.state,{contentPlayer:this.contentPlayer,getAdPlayer:()=>this.adPlayer,resolveAssetUri:(e,t)=>this.resolveAssetUri(e,t),liveEdgeDistanceSec:()=>this.resumeCoordinator.liveEdgeDistanceSec(),rebindContentElementIfSwapped:()=>this.rebindContentElementIfSwapped(),createAdAdapter:(e,t)=>this.createAdAdapter(e,t),reportAdProgress:e=>this.reportAdProgress(e),processTimedMetadata:e=>this.gamPodBridge.processTimedMetadata(e),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e),clearContentGate:()=>this.clearContentGate(),hide:()=>this.hide(),waitForLiveEdge:e=>this.resumeCoordinator.waitForLiveEdge(e),getVariant:e=>this.getVariant(e),getAssets:e=>this.getAssets(e)}),this.variantSelector=new b(this.state,{getEffectiveInsertionMode:()=>this.effectiveInsertionMode(),singleSurfaceDevice:this.singleSurfaceDevice,preloadMode:this.preloadMode,getIsContentPictureInPicture:()=>this.isContentPictureInPicture(),getIsGamReady:()=>this.isGamReady(),getSupportsParallelBuffering:()=>this.contentPlayer.supportsParallelBuffering,diagnose:(e,t,r)=>this.diagnose(e,t,r)}),this.assetPlayback=new B(this.state,{getAdPlayer:()=>this.adPlayer,getAdContainer:()=>this.adContainer,getAdMediaContainer:()=>this.adMediaContainer,clearStaticQuartiles:()=>this.staticQuartilesFired.clear(),getVariant:e=>this.getVariant(e),getGamEventCallbacks:()=>this.gamEventCallbacks,getSequencer:()=>this.sequencer,debug:this.debug,resolveUri:e=>this.resolveUri(e),buildGamUrl:(e,t)=>this.buildGamUrl(e,t),buildVastTagUrl:(e,t)=>this.buildVastTagUrl(e,t),onAdError:e=>this.onAdError(e),onAdEnded:()=>this.onAdEnded(),drive:e=>this.drive(e),clearOverlayImage:()=>this.clearOverlayImage(),revealFirstFrame:()=>this.preloader.revealFirstFrame(),transferPictureInPictureToAd:()=>this.presentationModes.transferPictureInPictureToAd(),isGamPodAsset:e=>this.isGamPodAsset(e),hasGamIdentityMismatch:e=>this.gamPodBridge.hasIdentityMismatch(e),beginGamPodTracking:e=>this.gamPodBridge.beginGamPodTracking(e),recordAdProgress:e=>this.adPlayerEvents.recordAdProgress(e),reportPhase:e=>this.reportPhase(e),armAdStartBudget:e=>this.armAdStartBudget(e),remainingAdStartBudgetMs:()=>this.remainingAdStartBudgetMs(),loadWithinBudget:(e,t)=>this.loadWithinBudget(e,t),waitForFirstFrame:()=>this.waitForFirstFrame(),getOverlayImage:()=>this.overlayImageEl,setOverlayImage:e=>{this.overlayImageEl=e},getImageAssetTimer:()=>this.imageAssetTimer,setImageAssetTimer:e=>{this.imageAssetTimer=e},getVastPodPosition:()=>this.vastPodPosition,setVastPodPosition:e=>{this.vastPodPosition=e},diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.breakSequenceDriver=new E(this.state,{getChainResolver:()=>this.chainResolver,getEffectiveInsertionMode:()=>this.effectiveInsertionMode(),getVastPodPosition:()=>this.vastPodPosition,setVastPodPosition:e=>{this.vastPodPosition=e},getPendingAdError:()=>this.pendingAdError,setPendingAdError:e=>{this.pendingAdError=e},getChaining:()=>this.chaining,setChaining:e=>{this.chaining=e},isExpandingPodAsset:e=>this.isExpandingPodAsset(e),fallBackToPodLevelReporting:()=>this.fallBackToPodLevelReporting(),resetGamPodTracking:()=>this.resetGamPodTracking(),emitGamPodSteps:e=>this.gamPodBridge.emitGamPodSteps(e),playAsset:(e,t,r)=>this.playAsset(e,t,r),endBreak:()=>this.endBreak(),playBreak:(e,t,r)=>this.playBreak(e,t,r),diagnose:(e,t,r)=>this.diagnose(e,t,r),log:(...e)=>this.log(...e)}),this.adPlayerEvents=new F(this.state,{getAdPlayer:()=>this.adPlayer,getContentPlayer:()=>this.contentPlayer,getGamEventCallbacks:()=>this.gamEventCallbacks,getSequencer:()=>this.sequencer,getAudioFocus:()=>this.audioFocus,getSyncing:()=>this.syncing,setSyncing:e=>{this.syncing=e},setAdVolumeChangeHandler:e=>{this.adVolumeChangeHandler=e},setContentVolumeHandler:e=>{this.contentVolumeHandler=e},notifyVolumeChange:()=>this.notifyVolumeChange(),onAdEnded:()=>this.onAdEnded(),processTimedMetadata:e=>this.gamPodBridge.processTimedMetadata(e),toAdError:e=>this.toAdError(e),revealFirstFrame:()=>this.revealFirstFrame(),clearFirstFrameResolver:()=>this.preloader.clearFirstFrameResolver(),drive:e=>this.drive(e),setPendingAdError:e=>{this.pendingAdError=e},log:(...e)=>this.log(...e),maybePrepositionContentForResume:()=>"single-decoder"!==this.preloadMode&&this.resumeCoordinator.maybePrepositionContentForResume(),maybeCatchUpContentForResume:e=>"single-decoder"!==this.preloadMode&&this.resumeCoordinator.maybeCatchUpContentForResume(e),getStaticQuartilesFired:()=>this.staticQuartilesFired,onGamPodAdProgress:e=>this.gamPodBridge.onGamPodAdProgress(e)})}setGamEventCallbacks(e){this.gamPodBridge.setEventCallbacks(e)}setDiagnoseHandler(e){this.diagnoseHandler=e}diagnose(e,t,r){this.diagnoseHandler?.(e,t,r)}holdContentForPreRoll(e){if(this.preRollHoldActive)return;const t=this.getVariant(e);t&&this.shouldPauseContent(t.format)&&(this.preRollHoldActive=!0,this.contentPlayer.pause(),this.preRollHoldHandler=()=>{this.preRollHoldActive&&this.contentPlayer.pause()},this.contentPlayer.on("playing",this.preRollHoldHandler),this.diagnose("DA-PREROLL-CONTENT-HELD","Content held at session start until the pending pre-roll begins.",{breakId:e.id}))}releaseContentHold(){this.preRollHoldActive&&(this.preRollHoldActive=!1,this.preRollHoldHandler&&(this.contentPlayer.off("playing",this.preRollHoldHandler),this.preRollHoldHandler=null))}gateContentForBreak(){this.contentPlayer.pause(),this.breakContentGateHandler||(this.breakContentGateHandler=()=>{this.contentPaused&&!this.state.resumeCatchupActive&&this.contentPlayer.pause()},this.contentPlayer.on("playing",this.breakContentGateHandler))}clearContentGate(e=!1){this.resumeCoordinator.endResumeCatchup(e),this.breakContentGateHandler&&(this.contentPlayer.off("playing",this.breakContentGateHandler),this.breakContentGateHandler=null)}setChainResolver(e){this.chainResolver=e}setResumeCueAnchorResolver(e){this.resumeCoordinator.setCueAnchorResolver(e)}setResumeCueEndResolver(e){this.resumeCoordinator.setCueEndResolver(e)}ingestStreamClockCue(e){this.resumeCoordinator.ingestStreamClockCue(e)}setTransitionPhaseReporter(e){this.transitionPhaseReporter=e}reportPhase(e){this.transitionPhaseReporter?.(e)}setBreakResumePolicy(e,t,r=!1){this.adInsertionType=e,this.breakTimebase=t,this.state.continueContentDuringBreak=r,this.state.continueRefusalReported=!1}initialize(){this.adContainer||(this.setupOverlay(),this.presentationModes.setupPictureInPictureTracking(),"adaptive"===this.insertionMode&&this.presentationModes.setupFullscreenTracking())}async startGamSession(e,t){await this.gamPodBridge.startGamSession(e,t)}endGamSession(){this.gamPodBridge.endGamSession()}setSessionAssetParameters(e){this.assetParameters.setSessionAssetParameters(e)}setManifestAssetParameters(e){this.assetParameters.setManifestAssetParameters(e)}updateAssetParameters(e){this.assetParameters.updateAssetParameters(e)}resolveExternalVendorConfiguration(e){return this.assetParameters.resolveExternalVendorConfiguration(e)}updateAssetParameterMacros(e){this.assetParameters.updateAssetParameterMacros(e)}get updatedAssetParameters(){return this.state.updatedAssetParameters}setSessionAssetParameterMacros(e){this.assetParameters.setSessionAssetParameterMacros(e)}get sessionAssetParameterMacros(){return this.assetParameters.getSessionAssetParameterMacros()}buildVastTagUrl(e,t){return this.assetParameters.buildVastTagUrl(e,t)}pushAssetParameters(e,t){this.assetParameters.pushAssetParameters(e,t)}setupOverlay(){this.adStage.setupOverlay()}isGamPodAsset(e){return this.gamPodBridge.isGamPodAsset(e)}isExpandingPodAsset(e){return this.gamPodBridge.isExpandingPodAsset(e)}fallBackToPodLevelReporting(){this.gamPodBridge.fallBackToPodLevelReporting()}resetGamPodTracking(){this.gamPodBridge.resetGamPodTracking()}emitGamPodSteps(e){this.gamPodBridge.emitGamPodSteps(e)}isGamEnabled(){return this.gamPodBridge.isGamEnabled()}isGamReady(){return this.gamPodBridge.isGamReady()}isOverlayInsertion(){return"overlay"===this.effectiveInsertionMode()}settleAssetProgress(){this.adPlayerEvents.settleAssetProgress()}reportAdProgress(e){this.adPlayerEvents.reportAdProgress(e)}setupEventListeners(){this.adPlayerEvents.setupEventListeners()}async preload(e){return this.preloader.preload(e)}renderLshapeContentBackdrop(e){this.adStage.renderLshapeContentBackdrop(e)}currentInsertionMode(){return this.presentationModes.currentInsertionMode()}effectiveInsertionMode(){return this.presentationModes.effectiveInsertionMode()}isContentPictureInPicture(){return this.presentationModes.isPictureInPicture()}rebindContentElementIfSwapped(){this.presentationModes.rebindContentElementIfSwapped()}teardownFullscreenTracking(){this.presentationModes.teardownFullscreenTracking()}teardownPictureInPictureTracking(){this.presentationModes.teardownPictureInPictureTracking()}isPictureInPicture(){return this.presentationModes.isPictureInPicture()}pictureInPictureOwner(){return this.presentationModes.pictureInPictureOwner()}isShowingAd(){if(!this.isAdPlaying())return!1;const e=this.currentDeclaredFormat();return!n(e,this.isContentPictureInPicture())}currentDeclaredFormat(){return this.currentSelectedFormat??(this.currentBreak?l(this.currentBreak):void 0)}async playBreak(t,s,a){if(this.state.preloadGeneration++,this.resumeGeneration++,!this.sharedElementPlayer.beginSharedActivity())return;this.releaseContentHold(),this.rebindContentElementIfSwapped();const n=a?.effectiveDurationSec??null;this.effectiveBreakDurationSec=null!==n&&n>0?n:null;const d=this.effectiveBreakDurationSec??t.duration;if("shared-element"===this.effectiveInsertionMode())return g(this.state),void await this.sharedElementPlayer.playSharedElementBreak(t,s);if(!this.adPlayer)return void this.log("playBreak called before initialize()");const l=this.getVariant(t);if(!l)return void this.log("No valid variant found for break:",t.id);this.currentBreak=t,this.callbacks=s,this.isPlaying=!0,this.firstFrameGateActive=a?.firstFrameGate??!1,this.firstFrameGateShown=!1;const h=this.continueContentDuringBreakReason(l.format),u=r(t),c=this.shouldPauseContent(l.format)&&"ok"===h&&!u;c||u||this.state.continueRefusalReported||!this.shouldPauseContent(l.format)||(this.state.continueRefusalReported=!0,this.diagnose("DA-CONTINUE-PLAYOUT-REFUSED",`Content will be paused for breaks this session: ${h}`,{reason:h,format:l.format})),this.audioFocus=l.format===e.DOUBLE?this.doubleBoxAudio:c?"ad":null,this.adPlayer&&("content"===this.audioFocus?(this.adPlayer.muted=!0,this.adPlayer.volume=0):(this.adPlayer.muted=this.contentPlayer.muted,this.adPlayer.volume=this.contentPlayer.volume,"ad"===this.audioFocus&&(this.contentPlayer.muted=!0)));const m=this.declaredFormatOf(t);if(this.currentSelectedFormat=m,this.state.pipAdoptedForBreak=i(m,this.isContentPictureInPicture()),this.state.pipAdoptedForBreak&&this.diagnose("DA-PIP-FORMAT-OVERRIDE",`Picture-in-picture: ${m} break plays as single`,{declared:m,effective:e.SINGLE,reason:"picture-in-picture",midBreak:!1}),this.shouldPauseContent(l.format)?(this.resumeCoordinator.captureBreakAnchor(t),c?(this.contentPaused=!1,this.resumeCoordinator.beginContinueContentPlayout()):(this.contentPaused=!0,this.gateContentForBreak())):this.contentPaused=!1,this.applyLayout(l),l.format===e.LSHAPE_CONTENT)return this.renderLshapeContentBackdrop(l),void(d&&d>0?(this.log("Starting duration timer:",d,"seconds"),this.durationTimer=setTimeout(()=>{this.log("Duration timer expired, ending break"),this.endBreak()},1e3*d)):this.endBreak());this.firstFrameGateActive||(this.show(),this.reapplyAdContainerLayout(l));if(0===this.getAssets(t).length)return this.log("No assets in break, ending immediately"),void this.endBreak();{const e=Math.max(0,d||0)+this.adBreakCutSafetyMarginSec;T(this.state,e,()=>{this.log("Break-cut timer expired, ending break"),this.firstFrameRejector?this.onAdError(new R("Break cut before first frame rendered","DA-AD-START-TIMEOUT")):this.sequencer&&this.currentBreak&&this.isPlaying?(this.callbacks?.onBreakCut?.(this.currentBreak),this.drive(this.sequencer.onOutcome({kind:"break-elapsed"}))):this.endBreak()},()=>this.onAdError(new R("Ad playback startup timed out","DA-AD-START-TIMEOUT")))}this.sequencer=new o("overlay",()=>null,this.selectionInputs()),await this.drive(this.sequencer.beginBreak(t)),this.preloadChainedSuccessor(t.id)}get resumeHandoverInMotion(){return this.state.resumeCatchupActive}reapplyAdContainerLayout(e){this.adStage.reapplyAdContainerLayout(e)}adoptPictureInPictureMidBreak(){this.presentationModes.adoptPictureInPictureMidBreak()}async restorePictureInPictureToContent(){await this.presentationModes.restorePictureInPictureToContent()}continueContentDuringBreakReason(e){return this.variantSelector.continueContentDuringBreakReason(e)}shouldPauseContent(t){return t===e.SINGLE||t===e.LSHAPE_AD}selectionInputs(){return this.variantSelector.selectionInputs()}breakNothingToPlayReason(e){return this.variantSelector.breakNothingToPlayReason(e)}unknownVariantFormatsOf(e){return this.variantSelector.unknownVariantFormatsOf(e)}diagnoseUnknownVariantFormats(e){this.variantSelector.diagnoseUnknownVariantFormats(e)}declaredFormatOf(e){const{selected:t,deviceQualified:r}=h(e,this.selectionInputs());return(t??r)?.format??l(e)}getVariant(e){return this.variantSelector.getVariant(e)}applyLayout(e){this.adStage.applyLayout(e)}restoreLayout(e){this.adStage.restoreLayout(e)}getAssets(e){return d(this.getVariant(e))}async playAsset(e,t,r){return this.assetPlayback.playAsset(e,t,r)}clearOverlayImage(){this.adStage.clearOverlayImage()}async showPauseImage(e){return this.pauseAdPresenter.showPauseImage(e)}hidePauseImage(){this.pauseAdPresenter.hidePauseImage()}async drive(e){return this.breakSequenceDriver.drive(e)}emitStep(e){this.breakSequenceDriver.emitStep(e)}async resolveAssetUri(e,t){return this.assetPlayback.resolveAssetUri(e,t)}async buildGamUrl(e,t){return this.gamPodBridge.buildGamUrl(e,t)}resolveUri(e){return this.assetParameters.resolveUri(e)}adPlayerStreamRemainingSec(){return this.assetPlayback.adPlayerStreamRemainingSec()}onAdEnded(){this.currentBreak&&this.isPlaying&&this.sequencer&&(this.settleAssetProgress(),this.drive(this.sequencer.onOutcome({kind:"asset-ended"})))}toAdError(e){return this.assetPlayback.toAdError(e)}onAdError(e){this.adPlayerEvents.onAdError(e)}endBreak(){if(!this.currentBreak)return;this.log("Break ended:",this.currentBreak.id),M(this.state),this.state.gamPodTracker&&this.emitGamPodSteps(this.state.gamPodTracker.finish()),this.resetGamPodTracking(),this.pushAssetParameters(void 0);const e=this.currentBreak,s=this.getVariant(e)?.format;let a=this.abortingBreak?null:this.resolveChainedSuccessor(e.id);if(a){const e=this.breakNothingToPlayReason(a);this.diagnoseUnknownVariantFormats(a),e&&(this.diagnose("DA-BREAK-NO-PLAYABLE-ASSET",`chained break ${a.id} has no playable variant (${e}); it will not begin.`,{breakId:a.id,reason:e}),this.callbacks?.onAdError(a,void 0,new R(`Break ${a.id} has no playable variant (${e})`,"DA-BREAK-NO-PLAYABLE-ASSET")),this.callbacks?.onChainedBreakSkipped?.(a),a=null)}if(a)return void this.advanceToChainedBreak(e,a);if(this.currentSelectedFormat=void 0,this.resumeCoordinator.endContinueContentPlayout(),this.restorePictureInPictureToContent(),this.isPlaying=!1,this.currentBreak=null,this.resumeGeneration++,this.effectiveBreakDurationSec=null,g(this.state),this.preloader.clearWarmedBreaks(),this.firstFrameGateActive=!1,this.firstFrameGateShown=!1,this.clearFirstFrame("Break ended before first frame"),"ad"===this.audioFocus&&this.adPlayer?(this.contentPlayer.muted=this.adPlayer.muted,this.contentPlayer.volume=this.adPlayer.volume):"content"===this.audioFocus&&this.adPlayer&&(this.adPlayer.muted=this.contentPlayer.muted,this.adPlayer.volume=this.contentPlayer.volume),this.audioFocus=null,this.clearOverlayImage(),this.vastAdManager?.reset(),this.hide(),this.restoreLayout(s),this.adPlayer?.pause(),this.state.sharedAdClaimActive){const t=this.callbacks;return this.sharedElementPlayer.detachSharedAdListeners(),this.abortingBreak=!1,this.state.earlyReturnResumeOffsetSec=null,this.sharedElementPlayer.restoreSharedElementContent(e),void t?.onBreakEnd(e)}const i="recreate"===this.recoveryDeps.contentRecovery&&"function"==typeof this.contentPlayer.recreateMediaPipeline,n="single-decoder"===this.preloadMode||i?this.adPlayer?.unload?.():void 0;if(this.contentPaused&&r(e))this.contentPaused=!1,this.clearContentGate();else if(this.contentPaused){this.contentPaused=!1,this.clearContentGate(this.resumeHandoverInMotion);const r=this.resumeGeneration;S(this.recoveryDeps,{breakInfo:e,earlyReturnOffsetSec:this.state.earlyReturnResumeOffsetSec,isLiveResume:this.breakTimebase===t.WALLCLOCK,released:n,isCurrent:()=>r===this.resumeGeneration})}this.abortingBreak=!1,this.state.earlyReturnResumeOffsetSec=null,this.callbacks?.onBreakEnd(e)}currentAdAsset(){return this.isPlaying?this.currentAsset:null}skipBreak(){this.isPlaying&&(this.log("Skipping break:",this.currentBreak?.id),M(this.state),this.sequencer&&this.currentBreak?this.drive(this.sequencer.onOutcome({kind:"break-elapsed"})):this.endBreak())}abortBreak(e){this.isPlaying&&(this.log("Early return — break removed from manifest:",this.currentBreak?.id),this.state.earlyReturnResumeOffsetSec=Math.max(0,e),this.abortingBreak=!0,M(this.state),this.sequencer&&this.currentBreak?this.drive(this.sequencer.onOutcome({kind:"break-elapsed"})):this.endBreak())}stopActiveBreak(){g(this.state),this.sharedElementPlayer.cancelSharedRestore()&&this.isPlaying&&(this.log("Aborting active break on session end:",this.currentBreak?.id),M(this.state),this.sharedElementPlayer.detachSharedAdListeners(),this.sharedElementPlayer.releaseContentElementAdPlayer(),this.adPlayer?.pause(),this.clearOverlayImage(),this.vastAdManager?.reset(),this.hide(),this.restoreLayout(this.currentBreak?this.getVariant(this.currentBreak)?.format??void 0:void 0),this.isPlaying=!1,this.currentBreak=null,this.currentAsset=null,this.contentPaused=!1,this.clearContentGate(),this.resumeCoordinator.endContinueContentPlayout(),this.effectiveBreakDurationSec=null,this.firstFrameGateActive=!1,this.firstFrameGateShown=!1,this.clearFirstFrame("Break aborted before first frame"),this.audioFocus=null)}resolveChainedSuccessor(e){return this.breakSequenceDriver.resolveChainedSuccessor(e)}advanceToChainedBreak(e,t){this.breakSequenceDriver.advanceToChainedBreak(e,t)}preloadChainedSuccessor(e){this.preloader.preloadChainedSuccessor(e)}revealFirstFrame(){this.assetPlayback.revealFirstFrame()}armAdStartBudget(e){this.preloader.armAdStartBudget(e)}remainingAdStartBudgetMs(){return this.preloader.remainingAdStartBudgetMs()}loadWithinBudget(e,t){return this.preloader.loadWithinBudget(e,t)}async waitForFirstFrame(){return this.preloader.waitForFirstFrame()}clearFirstFrame(e="Break ended before first frame"){this.preloader.clearFirstFrame(e)}show(){this.adStage.show()}hide(){this.adStage.hide()}isAdPlaying(){return this.isPlaying}get muted(){return"content"===this.audioFocus?this.contentPlayer.muted:"ad"===this.audioFocus?this.adPlayer?this.adPlayer.muted:this.contentPlayer.muted:this.isPlaying&&this.adPlayer?this.adPlayer.muted:this.contentPlayer.muted}set muted(e){if("content"===this.audioFocus)this.contentPlayer.muted=e;else if("ad"===this.audioFocus)this.adPlayer&&(this.adPlayer.muted=e);else{(this.isPlaying&&this.adPlayer?this.adPlayer:this.contentPlayer).muted=e}this.vastAdManager?.setMuted(e),this.notifyVolumeChange()}get volume(){return"content"===this.audioFocus?this.contentPlayer.volume:"ad"===this.audioFocus?this.adPlayer?this.adPlayer.volume:this.contentPlayer.volume:this.isPlaying&&this.adPlayer?this.adPlayer.volume:this.contentPlayer.volume}set volume(e){if("content"===this.audioFocus)this.contentPlayer.volume=e;else if("ad"===this.audioFocus)this.adPlayer&&(this.adPlayer.volume=e);else{(this.isPlaying&&this.adPlayer?this.adPlayer:this.contentPlayer).volume=e}this.vastAdManager?.setVolume(e),this.notifyVolumeChange()}setVolumeChangeCallback(e){this.volumeChangeCallback=e}notifyVolumeChange(){this.volumeChangeCallback?.(this.muted,this.volume)}destroy(){if(this.destroyed)return;if(this.resumeGeneration++,g(this.state),!this.sharedElementPlayer.beginSharedActivity())return;this.destroyed=!0,this.adStage.destroy(),this.resumeCoordinator.cancelResumeLandedProbe(),this.resumeCoordinator.dispose(),this.resumeCoordinator.endResumeCatchup(),this.resumeCoordinator.endContinueContentPlayout(),this.state.resumePrepositionSettle&&(clearTimeout(this.state.resumePrepositionSettle),this.state.resumePrepositionSettle=null),this.releaseContentHold(),this.clearContentGate(),this.clearFirstFrame("Controller destroyed before first frame"),this.firstFrameGateActive=!1,this.firstFrameGateShown=!1,this.resetGamPodTracking(),M(this.state),this.companionRemoveTimer&&(clearTimeout(this.companionRemoveTimer),this.companionRemoveTimer=null),this.adFadeTimer&&(clearTimeout(this.adFadeTimer),this.adFadeTimer=null),this.adPlayer?.pause(),this.clearOverlayImage(),this.pauseAdPresenter.destroy(),this.contentVolumeHandler&&(this.contentPlayer.off("volumechange",this.contentVolumeHandler),this.contentVolumeHandler=null),this.sharedElementPlayer.detachSharedAdListeners(),this.sharedElementPlayer.releaseContentElementAdPlayer(),this.state.pipTransferredToAd=!1,this.teardownFullscreenTracking(),this.teardownPictureInPictureTracking(),this.adVolumeChangeHandler&&this.adPlayer&&this.adPlayer.off("volumechange",this.adVolumeChangeHandler),this.adVolumeChangeHandler=null,this.hide(),this.adStage.destroy(),this.resizeObserver?.disconnect(),this.resizeObserver=null,this.contentVideoMutationObserver?.disconnect(),this.contentVideoMutationObserver=null,this.contentVideoElement&&this.contentVideoGeometryHandler&&(this.contentVideoElement.removeEventListener("loadedmetadata",this.contentVideoGeometryHandler),this.contentVideoElement.removeEventListener("resize",this.contentVideoGeometryHandler)),this.contentVideoElement=null,this.contentVideoGeometryHandler=null;const e=this.adStage.restoreContent(this.playerContainerCreatedBySDK,this.playerContainerOriginalStyle);this.companionElement&&this.companionElement.parentElement&&(this.companionElement.parentElement.removeChild(this.companionElement),this.companionElement=null),this.isPlaying=!1,this.currentBreak=null,this.adContainer&&this.adContainer.parentElement&&this.adContainer.parentElement.removeChild(this.adContainer),!e&&this.stage&&this.stage.parentElement&&this.stage.parentElement.removeChild(this.stage),this.stage=null,this.adContainer=null,this.adMediaContainer=null;try{this.adPlayer?.destroy()}catch(e){this.log("Ad player adapter destroy failed (ignored):",e)}this.adPlayer=null,this.callbacks=null,this.gamPodBridge.destroy(),this.vastAdManager?.destroy(),this.vastAdManager=null,this.log("Ad player destroyed")}log(...e){this.debug&&u("[OptiViewAds:AdPlayerController]",...e)}}AdPlayerController.AD_START_BUDGET_MS=5e3,AdPlayerController.GAM_POD_AD_START_BUDGET_MS=1e4,AdPlayerController.MIN_AD_START_BUDGET_MS=3e3;
@@ -1,61 +1,12 @@
1
1
  import { PlayerAdapter } from '../interfaces/PlayerAdapter';
2
+ import type { AdBreakSkipReason } from '../types/Events';
2
3
  import { Break, BreakManifest } from '../types/BreakManifest';
3
4
  import { type ResolvedBreakWarnings } from '../types/OptiViewAdsConfig';
4
5
  import type { MetadataCueTracker } from './MetadataCueTracker';
5
- /** Wallclock time source, so a driver (e.g. the conformance harness) can step time deterministically. */
6
- export interface Clock {
7
- /** Current wallclock time in milliseconds since the epoch. */
8
- now(): number;
9
- }
10
- /** Default {@link Clock} backed by `Date.now()`. */
11
- export declare const systemClock: Clock;
12
- export declare enum BreakState {
13
- /** Break is known but not yet due */
14
- PENDING = "pending",
15
- /** Claimed as part of a chain; the chain advance plays it, so the time-based check must not trigger it. */
16
- CHAINED = "chained",
17
- /** Break is currently active */
18
- ACTIVE = "active",
19
- /** Break has been completed */
20
- COMPLETED = "completed",
21
- /** Break was skipped (e.g., already passed) */
22
- SKIPPED = "skipped"
23
- }
24
- /** Tune-in (join-in-progress) configuration. */
25
- export interface TuneInOptions {
26
- /** Whether tune-in breaks are detected and triggered. */
27
- enabled: boolean;
28
- /** Minimum remaining seconds for a join-in-progress break to still be triggered; below this it is skipped. */
29
- minBreakDurationSeconds: number;
30
- }
31
- /**
32
- * How a break was triggered. `remainingSec` is always the MEASURED time left. `tuneIn`
33
- * describes the JOIN, not the playback: do not gate the effective duration on it, a viewer
34
- * inside the start tolerance is also part-way in.
35
- */
36
- export interface BreakStartContext {
37
- /** True when the viewer joined while the break was already in progress. */
38
- tuneIn: boolean;
39
- /** Seconds already elapsed since the break's start (0 for on-time triggers). */
40
- elapsedSec: number;
41
- /** Effective remaining duration, in seconds, the break should be presented for. */
42
- remainingSec: number;
43
- }
44
- export type BreakStartCallback = (breakInfo: Break, context: BreakStartContext) => void;
45
- /**
46
- * Fired PRELOAD_AHEAD_SECONDS before a break. Return `false` if the preload cannot be accepted
47
- * now (e.g. an ad is playing); the scheduler retries on the next tick.
48
- */
49
- export type BreakApproachingCallback = (breakInfo: Break) => boolean | void;
50
- /** Fired once per configured warning threshold before a non-pre-roll break; pre-rolls are exempt. */
51
- export type BreakWarningCallback = (breakInfo: Break, warningSec: number, secondsUntil: number) => void;
52
- /**
53
- * The ACTIVE break disappeared from a polled manifest (spec "early return"): end it now and
54
- * resume at `break.start + seconds played`. Fired at most once per break.
55
- */
56
- export type BreakAbortedCallback = (breakInfo: Break) => void;
57
- /** Structured-diagnostic sink (e.g. DA-PDT-MISSING). Optional; absent means silent. */
58
- export type SchedulerDiagnose = (code: string, message: string, context?: Record<string, unknown>) => void;
6
+ import { type BreakAbortedCallback, type BreakApproachingCallback, type BreakStartCallback, type BreakWarningCallback, type Clock, type SchedulerDiagnose, type TuneInOptions } from './BreakSchedulerTypes';
7
+ export { BreakState, systemClock, type BreakAbortedCallback, type BreakApproachingCallback, type BreakStartCallback, type BreakStartContext, type BreakWarningCallback, type Clock, type SchedulerDiagnose, type TuneInOptions, } from './BreakSchedulerTypes';
8
+ /** Scheduling cadence; a break is discovered up to one interval late on the tick alone. */
9
+ export declare const TICK_INTERVAL_MS = 250;
59
10
  export declare class BreakScheduler {
60
11
  private player;
61
12
  private breaks;
@@ -63,10 +14,22 @@ export declare class BreakScheduler {
63
14
  private readonly timingDeps;
64
15
  private readonly rewind;
65
16
  private checkInterval;
17
+ /** One-shot re-check armed for a wallclock break due inside the next tick (see {@link nextStartDeadlineMs}). */
18
+ private startDeadline;
19
+ /**
20
+ * Milliseconds until the earliest pending wallclock break, when that is within one tick; null
21
+ * otherwise. Re-derived on every check from the stream's Program Date Time, so a driver that
22
+ * ticks the scheduler itself (native SDKs) can arm the same one-shot the web scheduler arms.
23
+ */
24
+ nextStartDeadlineMs: number | null;
66
25
  private onBreakStart;
67
26
  private onBreakApproaching;
68
27
  private onBreakWarning;
69
28
  private onBreakAborted;
29
+ private onBreakSkipped;
30
+ private breakStartsHeld;
31
+ private onAdStartDelayElapsed;
32
+ private adStartDelayElapsedNotified;
70
33
  /** Break ids whose early-return abort was already notified; polls keep arriving during the teardown. */
71
34
  private abortNotifiedBreakIds;
72
35
  private preloadedBreakIds;
@@ -150,21 +113,32 @@ export declare class BreakScheduler {
150
113
  * Unknown events are reported once and dropped, so they never fire as timeline breaks.
151
114
  */
152
115
  private isSchedulableEvent;
153
- private describeStart;
154
116
  /**
155
117
  * Content playback began (spec `event: 'start'`): pre-rolls may trigger and played time starts
156
118
  * counting. Once per session; a replay in the same session does not re-fire pre-rolls.
157
119
  */
158
120
  markPlaybackStart(): void;
121
+ setOnAdStartDelayElapsed(callback: (() => void) | null): void;
122
+ holdBreakStarts(): void;
123
+ releaseBreakStarts(): void;
124
+ areBreakStartsHeld(): boolean;
125
+ private notifyAdStartDelayElapsed;
159
126
  /**
160
127
  * Content playback ended (spec `event: 'end'`): post-rolls may trigger once their `delay` has
161
128
  * elapsed on the wallclock. A completed post-roll never replays (see {@link completedBreakIds}).
162
129
  */
163
130
  markPlaybackEnd(): void;
164
131
  /** Start monitoring for break start times. */
165
- start(onBreakStart: BreakStartCallback, onBreakApproaching?: BreakApproachingCallback, onBreakWarning?: BreakWarningCallback, onBreakAborted?: BreakAbortedCallback): void;
132
+ start(onBreakStart: BreakStartCallback, onBreakApproaching?: BreakApproachingCallback, onBreakWarning?: BreakWarningCallback, onBreakAborted?: BreakAbortedCallback, onBreakSkipped?: (brk: Break, reason: AdBreakSkipReason) => void): void;
166
133
  /** One scheduling check. Drivers (tests, conformance harness) call it directly to step time deterministically. */
167
134
  tick(): void;
135
+ /**
136
+ * Cut at the start, not on the tick after it: the 250ms interval discovers a wallclock start
137
+ * up to one interval late, so a break due before the next tick gets a one-shot check at its
138
+ * start. The interval stays the safety net; a driver without the interval ticks on its own.
139
+ */
140
+ private armStartDeadline;
141
+ private clearStartDeadline;
168
142
  stop(): void;
169
143
  completeBreak(breakId: string): void;
170
144
  /** Bracket a content RELOAD so the new stream's start is not read as a backward seek. `false` also discards the stale previous position. */
@@ -180,6 +154,7 @@ export declare class BreakScheduler {
180
154
  notifyResumeSeek(targetSeconds: number, breakEndSeconds: number): void;
181
155
  /** A viewer seek through the SDK: drop the resume-seek guard so the step is judged by the normal rules. */
182
156
  notifyViewerSeek(): void;
157
+ private skipBreak;
183
158
  private cleanupBreaks;
184
159
  getActiveBreak(): Break | null;
185
160
  /** Rounded seconds until a PENDING break starts, or `null`; refreshes the `upcoming` countdown without polling events. */
@@ -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,diagnoseAnvatoBreakEnd as c,getBreakStartTime as u,getCurrentTime as b,secondsUntilBreak as g}from"./breakTiming";import{RewindRearm as S}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 S({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.timing.anvatoEndDiagnosed.clear(),this.playbackEndedAtMs=null,this.rewind.beginChannel();const a=t?{...e,breaks:e.breaks.filter(e=>e.id!==t.id)}:e;this.updateManifest(a)}isSchedulableEvent(t){return!s(t.start)||t.start.event===e.START||t.start.event===e.END||(this.unsupportedEventBreakIds.has(t.id)||(this.unsupportedEventBreakIds.add(t.id),this.log(`⚠️ Break ignored: "${t.id}" (unsupported event trigger "${t.start.event}")`),this.diagnose?.("DA-BREAK-EVENT-UNSUPPORTED","Break triggered by an event this SDK version does not schedule; the break was ignored",{breakId:t.id,event:t.start.event})),!1)}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:g(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.ACTIVE&&this.timing.timebase===t.PTS&&c(this.timing,this.timingDeps,s.break),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 b(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:u(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.timing.anvatoEndDiagnosed.clear(),this.cueTracker?.clear()}checkWarnings(e,t){if(t<=0||0===this.breakWarnings.seconds.length)return;let a=this.breakWarningFired.get(e.id);a||(a=new Set,this.breakWarningFired.set(e.id,a));for(const i of this.breakWarnings.seconds)a.has(i)||t<=i&&(a.add(i),this.log(`Break warning for "${e.id}" (${t}s <= ${i}s)`),this.onBreakWarning?.(e,i,t))}log(...e){this.debug&&h("[OptiViewAds:BreakScheduler]",...e)}}
1
+ import{BreakEvent as e,Timebase as t,getBreakEvent as i,getPostRollDelay as a,getPreRollDelay as s,isEventTrigger as r,isPauseBreak as n}from"../types/BreakManifest";import{DEFAULT_BREAK_WARNINGS as d,DEFAULT_PDT_GRACE_SECONDS as l}from"../types/OptiViewAdsConfig";import{PTS_MATCH_TOLERANCE_SECONDS as h}from"./MetadataCueTracker";import{debugLog as o}from"../diagnostics/debugLog";import{createBreakTimingState as k,describeBreakStart as c,diagnoseAnvatoBreakEnd as u,getBreakStartTime as b,getCurrentTime as g,secondsUntilBreak as S}from"./breakTiming";import{RewindRearm as m}from"./RewindRearm";import{BreakState as p,systemClock as B}from"./BreakSchedulerTypes";export{BreakState,systemClock}from"./BreakSchedulerTypes";export const TICK_INTERVAL_MS=250;export class BreakScheduler{constructor(e,t=!1,i={enabled:!1,maxGapSeconds:0},a=B,s={enabled:!1,minBreakDurationSeconds:0},r=null,n=d,h=null,o=l){this.breaks=new Map,this.timing=k(),this.checkInterval=null,this.startDeadline=null,this.nextStartDeadlineMs=null,this.onBreakStart=null,this.onBreakApproaching=null,this.onBreakWarning=null,this.onBreakAborted=null,this.onBreakSkipped=null,this.breakStartsHeld=!1,this.onAdStartDelayElapsed=null,this.adStartDelayElapsedNotified=!1,this.abortNotifiedBreakIds=new Set,this.preloadedBreakIds=new Set,this.breakWarnings=d,this.breakWarningFired=new Map,this.completedBreakIds=new Set,this.unsupportedEventBreakIds=new Set,this.playbackEndedAtMs=null,this.anvatoEnteredDiagnosed=new Set,this.retiredBreaks=new Map,this.minSeenTime=null,this.JOIN_DISCRIMINATOR_SLACK_MS=1e3,this.WINDOW_ESCAPE_GRACE_MS=12e3,this.TIMING_TOLERANCE_MS=5e3,this.PRELOAD_AHEAD_SECONDS=8,this.contentReloading=!1,this.startupSeeking=!1,this.player=e,this.debug=t,this.chainingEnabled=i.enabled,this.maxChainGapMs=1e3*Math.max(0,i.maxGapSeconds),this.tuneInEnabled=s.enabled,this.minBreakDurationMs=1e3*Math.max(0,s.minBreakDurationSeconds),this.clock=a,this.diagnose=r,this.breakWarnings=n,this.cueTracker=h;const c=Math.max(0,o);this.timingDeps={player:this.player,clock:this.clock,cueTracker:this.cueTracker,diagnose:this.diagnose,log:(...e)=>this.log(...e),pdtGraceSeconds:c,pdtGraceMs:1e3*c},this.rewind=new m({breaks:this.breaks,retiredBreaks:this.retiredBreaks,completedBreakIds:this.completedBreakIds,preloadedBreakIds:this.preloadedBreakIds,timing:this.timing,clock:this.clock,log:(...e)=>this.log(...e),getBreakStartTime:e=>this.getBreakStartTime(e)})}claimChain(e){if(!this.chainingEnabled)return;let t=this.breaks.get(e)?.break??null;for(;t;){const e=this.findSuccessor(t);if(!e)break;const i=this.breaks.get(e.id);if(!i||i.state!==p.PENDING)break;i.state=p.CHAINED,this.log(`🔗 Break "${e.id}" claimed as chained after "${t.id}"`),t=e}}getChainedSuccessor(e){if(!this.chainingEnabled)return null;const t=this.breaks.get(e)?.break;return t?this.findSuccessor(t,[p.PENDING,p.CHAINED]):null}activateChainedBreak(e){const t=this.breaks.get(e);t&&(t.state=p.ACTIVE)}findSuccessor(e,t=[p.PENDING]){const i=this.getBreakStartTime(e);if(null===i)return null;const a=i+1e3*(e.duration??0);let s=null;for(const r of this.breaks.values()){if(r.break.id===e.id)continue;if(!t.includes(r.state))continue;const n=this.getBreakStartTime(r.break);if(null===n)continue;if(n<=i)continue;const d=n-a;d>this.maxChainGapMs||(d<-this.TIMING_TOLERANCE_MS||(!s||n<s.start)&&(s={break:r.break,start:n}))}return s?.break??null}updateManifest(e){this.timing.timebase=e.timebase;const t=this.rewind.adStartDelayMs;this.rewind.setAdStartDelayMs(1e3*Math.max(0,e.adStartDelay??0)),t>0&&0===this.rewind.adStartDelayMs&&this.notifyAdStartDelayElapsed();for(const t of e.breaks){if(n(t))continue;if(!this.isSchedulableEvent(t))continue;if(this.completedBreakIds.has(t.id))continue;const e=this.breaks.get(t.id);e?e.state===p.PENDING&&(e.break=t):(this.breaks.set(t.id,{break:t,state:p.PENDING}),this.log(`📅 Break scheduled: "${t.id}" at ${c(t)}`))}const i=new Set(e.breaks.map(e=>e.id));for(const[e,t]of this.breaks)i.has(e)||t.state!==p.ACTIVE||this.abortNotifiedBreakIds.has(e)||(this.abortNotifiedBreakIds.add(e),this.log("Break removed from manifest while active (early return):",e),this.diagnose?.("DA-BREAK-EARLY-RETURN","Active break removed from manifest; returning to content early",{breakId:e}),this.onBreakAborted?.(t.break));this.cleanupBreaks(i)}resetForChannelSwitch(e){const t=this.getActiveBreak();for(const e of[...this.breaks.keys()])e!==t?.id&&this.breaks.delete(e);for(const e of[...this.abortNotifiedBreakIds])e!==t?.id&&this.abortNotifiedBreakIds.delete(e);this.completedBreakIds.clear(),this.retiredBreaks.clear(),this.preloadedBreakIds.clear(),this.breakWarningFired.clear(),this.unsupportedEventBreakIds.clear(),this.anvatoEnteredDiagnosed.clear(),this.timing.anvatoPendingDiagnosed.clear(),this.timing.anvatoMatchedDiagnosed.clear(),this.timing.anvatoEndDiagnosed.clear(),this.playbackEndedAtMs=null,this.rewind.beginChannel();const i=t?{...e,breaks:e.breaks.filter(e=>e.id!==t.id)}:e;this.updateManifest(i)}isSchedulableEvent(t){return!r(t.start)||t.start.event===e.START||t.start.event===e.END||(this.unsupportedEventBreakIds.has(t.id)||(this.unsupportedEventBreakIds.add(t.id),this.log(`⚠️ Break ignored: "${t.id}" (unsupported event trigger "${t.start.event}")`),this.diagnose?.("DA-BREAK-EVENT-UNSUPPORTED","Break triggered by an event this SDK version does not schedule; the break was ignored",{breakId:t.id,event:t.start.event})),!1)}markPlaybackStart(){null!==this.playbackEndedAtMs&&(this.playbackEndedAtMs=null,this.log("Content replayed; pending post-rolls cancelled")),this.rewind.playbackStarted||(this.rewind.markPlaybackStart(this.peekPosition()),this.log("Content playback started at",new Date(this.clock.now()).toISOString()))}setOnAdStartDelayElapsed(e){this.onAdStartDelayElapsed=e}holdBreakStarts(){this.breakStartsHeld=!0}releaseBreakStarts(){this.breakStartsHeld=!1,this.checkBreaks()}areBreakStartsHeld(){return this.breakStartsHeld||this.rewind.isAdStartDelayActive()}notifyAdStartDelayElapsed(){this.adStartDelayElapsedNotified||(this.adStartDelayElapsedNotified=!0,this.onAdStartDelayElapsed?.())}markPlaybackEnd(){null===this.playbackEndedAtMs&&(this.playbackEndedAtMs=this.clock.now(),this.log("Content playback ended at",new Date(this.playbackEndedAtMs).toISOString()))}start(e,t,i,a,s){this.onBreakStart=e,this.onBreakApproaching=t??null,this.onBreakWarning=i??null,this.onBreakAborted=a??null,this.onBreakSkipped=s??null,this.checkInterval&&clearInterval(this.checkInterval),this.checkInterval=setInterval(()=>{this.tick()},250),this.log("Scheduler started")}tick(){this.checkBreaks(),null!==this.nextStartDeadlineMs&&this.armStartDeadline(this.nextStartDeadlineMs)}armStartDeadline(e){null!==this.checkInterval&&null===this.startDeadline&&(this.startDeadline=setTimeout(()=>{this.startDeadline=null,this.tick()},Math.max(1,Math.ceil(e))))}clearStartDeadline(){this.startDeadline&&clearTimeout(this.startDeadline),this.startDeadline=null}stop(){this.checkInterval&&(clearInterval(this.checkInterval),this.checkInterval=null),this.clearStartDeadline(),this.onBreakStart=null,this.onBreakSkipped=null,this.log("Scheduler stopped")}completeBreak(e){this.completedBreakIds.add(e),this.breakWarningFired.delete(e),this.abortNotifiedBreakIds.delete(e);const t=this.breaks.get(e);t&&(this.log("Break completed and removed:",e),null===i(t.break)&&null===this.cueTracker&&this.retiredBreaks.set(e,t.break),this.breaks.delete(e),this.preloadedBreakIds.delete(e))}setContentReloading(e){this.contentReloading=e,this.rewind.setContentReloading(e||this.startupSeeking)}setStartupSeeking(e){this.startupSeeking=e,this.rewind.setContentReloading(e||this.contentReloading)}notifyResumeSeek(e,t){this.rewind.notifyResumeSeek(e,t)}notifyViewerSeek(){this.rewind.notifyViewerSeek()}skipBreak(e,t){e.state=p.SKIPPED,this.completedBreakIds.add(e.break.id),this.onBreakSkipped?.(e.break,t)}cleanupBreaks(e){const t=[];for(const[i,a]of this.breaks)a.state!==p.COMPLETED&&a.state!==p.SKIPPED?e.has(i)||a.state===p.ACTIVE||(this.skipBreak(a,"removed"),t.push(i)):t.push(i);for(const e of t)this.breaks.delete(e),this.preloadedBreakIds.delete(e),this.breakWarningFired.delete(e)}getActiveBreak(){for(const e of this.breaks.values())if(e.state===p.ACTIVE)return e.break;return null}getSecondsUntilBreak(e){const t=this.breaks.get(e);if(!t||t.state!==p.PENDING)return null;const i=this.getCurrentTime();if(null===i)return null;const a=this.getBreakStartTime(t.break);return null===a?null:S(a,i)}notifyCuePresented(e){if(null===this.cueTracker||this.timing.timebase!==t.PTS)return null;if(!Number.isFinite(e))return null;let i=null;for(const t of this.breaks.values())if(t.state===p.PENDING&&"number"==typeof t.break.start&&!(Math.abs(t.break.start-e)>h)){i=t.break.id;break}if(null===i)return null;const a=this.player.currentTime;this.checkBreaks();const s=this.breaks.get(i);return s&&s.state===p.ACTIVE?this.anvatoEnteredDiagnosed.has(i)?null:(this.anvatoEnteredDiagnosed.add(i),this.log(`🎯 Break "${i}" armed by cue presentation (pts ${e})`),this.diagnose?.("DA-ANVATO-CUE-ENTERED",`Break "${i}" started from the presented cue (pts ${e}) rather than the scheduler tick.`,{breakId:i,pts:e,mediaTimeSec:a}),i):null}checkBreaks(){if(this.nextStartDeadlineMs=null,this.startupSeeking)return;const e=this.getCurrentTime();this.rewind.trackPlayedTime(e),this.rewind.adStartDelayMs>0&&!this.rewind.isAdStartDelayActive()&&this.notifyAdStartDelayElapsed();const i=this.areBreakStartsHeld();null!==e&&(this.minSeenTime=null===this.minSeenTime?e:Math.min(this.minSeenTime,e),this.rewind.rearmOnRewind(e));for(const r of this.breaks.values()){if(r.state===p.ACTIVE&&this.timing.timebase===t.WALLCLOCK&&null!==e&&!this.abortNotifiedBreakIds.has(r.break.id)){const t=this.getBreakStartTime(r.break),i=1e3*(r.break.duration??0);null!==t&&i>0&&e>t+i+this.WINDOW_ESCAPE_GRACE_MS&&(this.abortNotifiedBreakIds.add(r.break.id),this.log(`⚠️ Break window escaped: "${r.break.id}" (ended ${Math.round((e-t-i)/1e3)}s ago on the stream clock)`),this.diagnose?.("DA-BREAK-WINDOW-ESCAPED","Active break outlived its wallclock window; returning to content",{breakId:r.break.id,overrunSec:Math.round((e-t-i)/100)/10}),this.onBreakAborted?.(r.break));continue}if(r.state===p.ACTIVE&&this.timing.timebase===t.PTS&&u(this.timing,this.timingDeps,r.break),r.state!==p.PENDING)continue;const n=s(r.break);if(null!==n){this.checkPreRollBreak(r,n,i);continue}const d=a(r.break);if(null!==d){this.checkPostRollBreak(r,d,i);continue}if(null===e)continue;if(i)continue;null!==this.cueTracker&&this.timing.timebase===t.PTS&&this.maybePreload(r.break,"manifest arrival — Anvato flow");const l=this.getBreakStartTime(r.break);if(null===l)continue;const h=e-l,o=Math.round(-h/1e3);if(this.timing.timebase===t.WALLCLOCK&&h<0&&-h<=250&&(this.nextStartDeadlineMs=Math.min(this.nextStartDeadlineMs??1/0,-h)),this.checkWarnings(r.break,o),o>0&&o<=15&&o%2==0&&this.log(`⏱️ Break "${r.break.id}" starts in ${o}s`),o>0&&o<=this.PRELOAD_AHEAD_SECONDS&&this.maybePreload(r.break,`${o}s ahead`),h>=0&&h<=this.TIMING_TOLERANCE_MS){const e=Math.max(0,h),t=1e3*(r.break.duration??0)-e;if(t<=0){this.log(`⚠️ Break missed: "${r.break.id}" (ended ${Math.round(-t/1e3)}s ago, inside the start tolerance)`),this.skipBreak(r,t>0&&this.tuneInEnabled?"insufficient-remaining":"late"),null===this.cueTracker&&this.breaks.get(r.break.id)===r&&this.retiredBreaks.set(r.break.id,r.break);break}if(null!==this.minSeenTime&&l<this.minSeenTime-this.JOIN_DISCRIMINATOR_SLACK_MS&&(!this.tuneInEnabled||t<this.minBreakDurationMs)){this.log(`⚠️ Break missed: "${r.break.id}" (joined in progress inside the start tolerance, ${Math.round(t/1e3)}s remaining < tune-in rules)`),this.skipBreak(r,t>0&&this.tuneInEnabled?"insufficient-remaining":"late"),null===this.cueTracker&&this.breaks.get(r.break.id)===r&&this.retiredBreaks.set(r.break.id,r.break);break}this.log(`🎬 BREAK TRIGGERED: "${r.break.id}"`),r.state=p.ACTIVE,this.onBreakStart&&this.onBreakStart(r.break,{tuneIn:!1,elapsedSec:e/1e3,remainingSec:t/1e3});break}if(h>this.TIMING_TOLERANCE_MS){const t=l+1e3*(r.break.duration??0)-e;if(this.tuneInEnabled&&t>=this.minBreakDurationMs&&t>0){this.log(`🎬 TUNE-IN BREAK TRIGGERED: "${r.break.id}" (${Math.round(t/1e3)}s remaining)`),r.state=p.ACTIVE,this.onBreakStart&&this.onBreakStart(r.break,{tuneIn:!0,elapsedSec:h/1e3,remainingSec:t/1e3});break}this.log(`⚠️ Break missed: "${r.break.id}" (was ${Math.round(h/1e3)}s ago)`),this.skipBreak(r,t>0&&this.tuneInEnabled?"insufficient-remaining":"late"),null===this.cueTracker&&this.breaks.get(r.break.id)===r&&this.retiredBreaks.set(r.break.id,r.break)}}}checkPreRollBreak(e,t,i){if(!this.rewind.playbackStarted)return;const a=1e3*t;if(this.rewind.adStartDelayMs>0&&a<this.rewind.adStartDelayMs)return this.log(`⚠️ Pre-roll skipped: "${e.break.id}" (delay ${t}s < adStartDelay ${this.rewind.adStartDelayMs/1e3}s)`),void this.skipBreak(e,"start-delay");const s=this.rewind.channelPlayedMs,r=Math.round((a-s)/1e3);r>0&&r<=15&&r%2==0&&this.log(`⏱️ Pre-roll "${e.break.id}" starts in ${r}s`),r>0&&r<=this.PRELOAD_AHEAD_SECONDS&&this.maybePreload(e.break,`pre-roll, ${r}s ahead`),s>=a&&!i&&(this.log(`🎬 PRE-ROLL TRIGGERED: "${e.break.id}"${t>0?` (after ${t}s delay)`:""}`),e.state=p.ACTIVE,this.onBreakStart&&this.onBreakStart(e.break,{tuneIn:!1,elapsedSec:0,remainingSec:e.break.duration??0}))}checkPostRollBreak(e,t,i){if(null===this.playbackEndedAtMs)return;const a=1e3*t,s=this.clock.now()-this.playbackEndedAtMs,r=Math.round((a-s)/1e3);r>0&&r<=this.PRELOAD_AHEAD_SECONDS&&this.maybePreload(e.break,`post-roll, ${r}s ahead`),s>=a&&!i&&(this.log(`🎬 POST-ROLL TRIGGERED: "${e.break.id}"${t>0?` (after ${t}s delay)`:""}`),e.state=p.ACTIVE,this.onBreakStart&&this.onBreakStart(e.break,{tuneIn:!1,elapsedSec:0,remainingSec:e.break.duration??0}))}isAdStartDelayActive(){return this.areBreakStartsHeld()}getCurrentTime(){return g(this.timing,this.timingDeps)}maybePreload(e,t){if(this.preloadedBreakIds.has(e.id)||!this.onBreakApproaching)return;this.log(`⏳ Preloading break "${e.id}" (${t})`);!1!==this.onBreakApproaching(e)&&this.preloadedBreakIds.add(e.id)}getBreakStartTime(e){return r(e.start)?null:b(this.timing,this.timingDeps,e)}peekPosition(){if(this.timing.timebase!==t.WALLCLOCK)return 1e3*this.player.currentTime;const e=this.player.programDateTime?.getTime();return void 0===e||isNaN(e)?null:e}destroy(){this.stop(),this.breaks.clear(),this.preloadedBreakIds.clear(),this.completedBreakIds.clear(),this.retiredBreaks.clear(),this.minSeenTime=null,this.breakStartsHeld=!1,this.onAdStartDelayElapsed=null,this.adStartDelayElapsedNotified=!1,this.unsupportedEventBreakIds.clear(),this.playbackEndedAtMs=null,this.rewind.reset(),this.breakWarningFired.clear(),this.abortNotifiedBreakIds.clear(),this.timing.pdtMissingWarned=!1,this.timing.pdtSeen=!1,this.timing.firstPdtAttemptMs=null,this.timing.playbackStartedAtMs=null,this.timing.anvatoPendingDiagnosed.clear(),this.timing.anvatoMatchedDiagnosed.clear(),this.timing.anvatoEndDiagnosed.clear(),this.cueTracker?.clear()}checkWarnings(e,t){if(t<=0||0===this.breakWarnings.seconds.length)return;let i=this.breakWarningFired.get(e.id);i||(i=new Set,this.breakWarningFired.set(e.id,i));for(const a of this.breakWarnings.seconds)i.has(a)||t<=a&&(i.add(a),this.log(`Break warning for "${e.id}" (${t}s <= ${a}s)`),this.onBreakWarning?.(e,a,t))}log(...e){this.debug&&o("[OptiViewAds:BreakScheduler]",...e)}}
@@ -0,0 +1,55 @@
1
+ import type { Break } from '../types/BreakManifest';
2
+ /** Wallclock time source, so a driver (e.g. the conformance harness) can step time deterministically. */
3
+ export interface Clock {
4
+ /** Current wallclock time in milliseconds since the epoch. */
5
+ now(): number;
6
+ }
7
+ /** Default {@link Clock} backed by `Date.now()`. */
8
+ export declare const systemClock: Clock;
9
+ export declare enum BreakState {
10
+ /** Break is known but not yet due */
11
+ PENDING = "pending",
12
+ /** Claimed as part of a chain; the chain advance plays it, so the time-based check must not trigger it. */
13
+ CHAINED = "chained",
14
+ /** Break is currently active */
15
+ ACTIVE = "active",
16
+ /** Break has been completed */
17
+ COMPLETED = "completed",
18
+ /** Break was skipped (e.g., already passed) */
19
+ SKIPPED = "skipped"
20
+ }
21
+ /** Tune-in (join-in-progress) configuration. */
22
+ export interface TuneInOptions {
23
+ /** Whether tune-in breaks are detected and triggered. */
24
+ enabled: boolean;
25
+ /** Minimum remaining seconds for a join-in-progress break to still be triggered; below this it is skipped. */
26
+ minBreakDurationSeconds: number;
27
+ }
28
+ /**
29
+ * How a break was triggered. `remainingSec` is always the MEASURED time left. `tuneIn`
30
+ * describes the JOIN, not the playback: do not gate the effective duration on it, a viewer
31
+ * inside the start tolerance is also part-way in.
32
+ */
33
+ export interface BreakStartContext {
34
+ /** True when the viewer joined while the break was already in progress. */
35
+ tuneIn: boolean;
36
+ /** Seconds already elapsed since the break's start (0 for on-time triggers). */
37
+ elapsedSec: number;
38
+ /** Effective remaining duration, in seconds, the break should be presented for. */
39
+ remainingSec: number;
40
+ }
41
+ export type BreakStartCallback = (breakInfo: Break, context: BreakStartContext) => void;
42
+ /**
43
+ * Fired PRELOAD_AHEAD_SECONDS before a break. Return `false` if the preload cannot be accepted
44
+ * now (e.g. an ad is playing); the scheduler retries on the next tick.
45
+ */
46
+ export type BreakApproachingCallback = (breakInfo: Break) => boolean | void;
47
+ /** Fired once per configured warning threshold before a non-pre-roll break; pre-rolls are exempt. */
48
+ export type BreakWarningCallback = (breakInfo: Break, warningSec: number, secondsUntil: number) => void;
49
+ /**
50
+ * The ACTIVE break disappeared from a polled manifest (spec "early return"): end it now and
51
+ * resume at `break.start + seconds played`. Fired at most once per break.
52
+ */
53
+ export type BreakAbortedCallback = (breakInfo: Break) => void;
54
+ /** Structured-diagnostic sink (e.g. DA-PDT-MISSING). Optional; absent means silent. */
55
+ export type SchedulerDiagnose = (code: string, message: string, context?: Record<string, unknown>) => void;
@@ -0,0 +1 @@
1
+ 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={}));
@@ -0,0 +1,13 @@
1
+ import type { BreakManifest } from '../types/BreakManifest';
2
+ import type { ExternalVendorConfigurationsResult } from './resolveExternalVendorConfigurations';
3
+ import type { ExternalVendorConfiguration } from './resolveExternalVendorConfigurations';
4
+ import type { ExternalVendorConfigurationChangeEvent } from '../types/Events';
5
+ export declare class ExternalVendorConfigurationTracker {
6
+ private readonly emit;
7
+ private templates;
8
+ constructor(emit: (provider: string) => void);
9
+ get entries(): ExternalVendorConfiguration[];
10
+ adopt(manifest: BreakManifest): ExternalVendorConfigurationsResult;
11
+ reset(): void;
12
+ }
13
+ export declare function createExternalVendorConfigurationTracker(emit: (event: ExternalVendorConfigurationChangeEvent) => void): ExternalVendorConfigurationTracker;
@@ -0,0 +1 @@
1
+ import{changedExternalVendorProviders as e,resolveExternalVendorConfigurations as t}from"./resolveExternalVendorConfigurations";export class ExternalVendorConfigurationTracker{constructor(e){this.emit=e,this.templates=[]}get entries(){return this.templates.map(e=>({provider:e.provider,assetParameters:{...e.assetParameters}}))}adopt(r){const n=t(r),o=e(this.templates,n.entries);this.templates=n.entries;for(const e of o)this.emit(e);return n}reset(){this.templates=[]}}export function createExternalVendorConfigurationTracker(e){return new ExternalVendorConfigurationTracker(t=>e({type:"externalvendorconfigurationchange",provider:t,timestamp:Date.now()}))}
@@ -12,7 +12,9 @@ export interface GamAdEventCallbacks {
12
12
  onAdMidpoint?: () => void;
13
13
  onAdThirdQuartile?: () => void;
14
14
  onError?: (message: string) => void;
15
+ onDuplicateMetadata?: (startTime: number) => void;
15
16
  }
17
+ export declare const GAM_DUPLICATE_METADATA_DIAGNOSTIC_MESSAGE = "The stream carries the same ad marker more than once at the same time (for example in both the audio and video renditions of an fMP4 stream); the duplicate was not passed to IMA, so each ad event fires once. Reported once per stream session.";
16
18
  /** Configuration for GamStreamManager initialization. */
17
19
  export interface GamStreamConfig {
18
20
  networkCode: string;
@@ -37,6 +39,9 @@ export declare class GamStreamManager {
37
39
  private initPromise;
38
40
  private debug;
39
41
  private callbacks;
42
+ private metadataDeduplicator;
43
+ private markerTextDeduplicator;
44
+ private duplicateMetadataReported;
40
45
  constructor(videoElement: HTMLVideoElement, adUiContainer?: HTMLElement | undefined, debug?: boolean);
41
46
  /** Set callbacks for ad events. */
42
47
  setCallbacks(callbacks: GamAdEventCallbacks): void;
@@ -57,6 +62,7 @@ export declare class GamStreamManager {
57
62
  replaceAdTagParameters(params: Record<string, string>): void;
58
63
  /** Forward a timed-metadata marker to IMA for SSAI ad tracking. Prefers raw ID3 bytes (IMA parses them itself). */
59
64
  processTimedMetadata(cue: TimedMetadataCue): void;
65
+ private acceptMetadata;
60
66
  /** Build a pod manifest URL with the current streamId. Throws if not initialized. */
61
67
  buildPodUrl(podId: string, durationSeconds: number, params: GamVendorParameters): string;
62
68
  /** Reset before starting a new playback session. */