@dolby-optiview/ads-sdk-core 1.1.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/OptiViewAds.d.ts +8 -4
- package/dist/OptiViewAds.js +1 -1
- package/dist/OptiViewAdsExternalVendors.d.ts +47 -0
- package/dist/OptiViewAdsExternalVendors.js +1 -0
- package/dist/generated/diagnosticCodes.d.ts +72 -2
- package/dist/generated/diagnosticCodes.js +1 -1
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/id3/index.d.ts +1 -0
- package/dist/id3/index.js +1 -1
- package/dist/id3/parseId3TextFrames.d.ts +8 -0
- package/dist/id3/parseId3TextFrames.js +1 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.js +1 -1
- package/dist/interfaces/PlayerAdapter.d.ts +5 -0
- package/dist/services/AdBreakSequencer.js +1 -1
- package/dist/services/AdPlayerController.d.ts +2 -0
- package/dist/services/AdPlayerController.js +1 -1
- package/dist/services/BreakScheduler.d.ts +31 -56
- package/dist/services/BreakScheduler.js +1 -1
- package/dist/services/BreakSchedulerTypes.d.ts +55 -0
- package/dist/services/BreakSchedulerTypes.js +1 -0
- package/dist/services/ExternalVendorConfigurationTracker.d.ts +13 -0
- package/dist/services/ExternalVendorConfigurationTracker.js +1 -0
- package/dist/services/GamStreamManager.d.ts +6 -0
- package/dist/services/GamStreamManager.js +1 -1
- package/dist/services/ImaMetadataDeduplicator.d.ts +5 -0
- package/dist/services/ImaMetadataDeduplicator.js +1 -0
- package/dist/services/SsaiController.d.ts +2 -0
- package/dist/services/SsaiController.js +1 -1
- package/dist/services/adPlayer/AdPlayerEvents.js +1 -1
- package/dist/services/adPlayer/AdPlayerState.d.ts +13 -0
- package/dist/services/adPlayer/AdPlayerState.js +1 -1
- package/dist/services/adPlayer/AdPreloader.js +1 -1
- package/dist/services/adPlayer/AdStage.d.ts +7 -3
- package/dist/services/adPlayer/AdStage.js +1 -1
- package/dist/services/adPlayer/AssetParameterResolver.d.ts +2 -0
- package/dist/services/adPlayer/AssetParameterResolver.js +1 -1
- package/dist/services/adPlayer/AssetPlayback.js +1 -1
- package/dist/services/adPlayer/ContentResumeCoordinator.d.ts +10 -3
- package/dist/services/adPlayer/ContentResumeCoordinator.js +1 -1
- package/dist/services/adPlayer/GamPodBridge.js +1 -1
- package/dist/services/adPlayer/SharedElementBreakPlayer.js +1 -1
- package/dist/services/adPlayer/VariantSelector.js +1 -1
- package/dist/services/adPlayer/pdtClockResume.d.ts +57 -0
- package/dist/services/adPlayer/pdtClockResume.js +1 -0
- package/dist/services/assetParameterMacros.d.ts +0 -1
- package/dist/services/assetParameterMacros.js +1 -1
- package/dist/services/breakTiming.d.ts +2 -0
- package/dist/services/breakTiming.js +1 -1
- package/dist/services/channelSwitch.d.ts +3 -1
- package/dist/services/channelSwitch.js +1 -1
- package/dist/services/detectDeviceType.d.ts +7 -2
- package/dist/services/detectDeviceType.js +1 -1
- package/dist/services/diagnosticReport.d.ts +3 -0
- package/dist/services/diagnosticReport.js +1 -0
- package/dist/services/externalVendorConfigurationGetter.d.ts +12 -0
- package/dist/services/externalVendorConfigurationGetter.js +1 -0
- package/dist/services/matchTargeting.d.ts +19 -0
- package/dist/services/matchTargeting.js +1 -0
- package/dist/services/resolveDeliveryMode.d.ts +3 -1
- package/dist/services/resolveDeliveryMode.js +1 -1
- package/dist/services/resolveExternalVendorConfigurations.d.ts +20 -0
- package/dist/services/resolveExternalVendorConfigurations.js +1 -0
- package/dist/services/resolveGamVendorConfiguration.js +1 -1
- package/dist/services/resolveResumeClamp.d.ts +42 -0
- package/dist/services/resolveResumeClamp.js +1 -0
- package/dist/services/resolveTargetedUri.d.ts +2 -1
- package/dist/services/resolveTargetedUri.js +1 -1
- package/dist/services/selectVariant.d.ts +4 -0
- package/dist/services/selectVariant.js +1 -1
- package/dist/services/toPlaybackError.d.ts +1 -0
- package/dist/services/toPlaybackError.js +1 -0
- package/dist/services/wallclockBreakWindow.d.ts +41 -0
- package/dist/services/wallclockBreakWindow.js +1 -0
- package/dist/session/BreakLifecycle.d.ts +2 -0
- package/dist/session/BreakLifecycle.js +1 -1
- package/dist/session/SessionStarter.d.ts +6 -1
- package/dist/session/SessionStarter.js +1 -1
- package/dist/session/SessionState.d.ts +1 -0
- package/dist/session/SessionState.js +1 -1
- package/dist/types/BreakManifest.d.ts +39 -1
- package/dist/types/BreakManifest.js +1 -1
- package/dist/types/Events.d.ts +16 -1
- package/dist/types/ExternalVendorConfiguration.d.ts +5 -0
- package/dist/types/ExternalVendorConfiguration.js +1 -0
- package/dist/types/OptiViewAdsConfig.d.ts +2 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BreakFormat as e}from"../types/BreakManifest";import{playbackErrorContext as t}from"../diagnostics/playbackErrorContext";import{adErrorCode as a}from"../types/AdError";import{VendorAdError as i}from"../types/VendorAdError";export class BreakLifecycle{constructor(e,t){this.state=e,this.deps=t,this.breakBeginEmittedId=null,this.pendingAdBreakBegin=null}emitAdBreakBegin(e,t){this.breakBeginEmittedId!==e.id&&(this.breakBeginEmittedId=e.id,this.pendingAdBreakBegin=null,this.deps.emit("adbreakbegin",{type:"adbreakbegin",timestamp:Date.now(),break:e,format:this.deps.effectiveFormatOf(e),elapsedSec:t?.elapsedSec??0,remainingSec:t?.remainingSec??e.duration??0,...t?.tuneIn?{tuneIn:{elapsedSec:t.elapsedSec,remainingSec:t.remainingSec}}:{}}))}flushPendingAdBreakBegin(){this.pendingAdBreakBegin?.()}async onBreakStart(d
|
|
1
|
+
import{BreakFormat as e}from"../types/BreakManifest";import{playbackErrorContext as t}from"../diagnostics/playbackErrorContext";import{adErrorCode as a}from"../types/AdError";import{VendorAdError as i}from"../types/VendorAdError";export class BreakLifecycle{constructor(e,t){this.state=e,this.deps=t,this.breakBeginEmittedId=null,this.pendingAdBreakBegin=null}emitAdBreakBegin(e,t){this.breakBeginEmittedId!==e.id&&(this.breakBeginEmittedId=e.id,this.pendingAdBreakBegin=null,this.deps.emit("adbreakbegin",{type:"adbreakbegin",timestamp:Date.now(),break:e,format:this.deps.effectiveFormatOf(e),elapsedSec:t?.elapsedSec??0,remainingSec:t?.remainingSec??e.duration??0,...t?.tuneIn?{tuneIn:{elapsedSec:t.elapsedSec,remainingSec:t.remainingSec}}:{}}))}flushPendingAdBreakBegin(){this.pendingAdBreakBegin?.()}onBreakSkipped(e,t){this.deps.emit("adbreakskipped",{type:"adbreakskipped",timestamp:Date.now(),break:e,reason:t,format:this.deps.effectiveFormatOf(e)})}async onBreakStart(r,d){const s=this.state.sessionGeneration;if(this.state.snapbackSeekInFlight=!1,this.deps.adPlayerController.isAdPlaying()){if(this.deps.diagnose("DA-BREAK-SUPPRESSED-OVERLAP",`Break suppressed (ad already playing): ${r.id}`,{breakId:r.id}),s!==this.state.sessionGeneration)return;return this.deps.breakScheduler.completeBreak(r.id),this.onBreakSkipped(r,"overlap"),void this.deps.onBreakSettled?.()}this.deps.adPlayerController.diagnoseUnknownVariantFormats(r);const n=this.deps.adPlayerController.breakNothingToPlayReason(r);if(n){if(this.deps.log("Break not begun (no playable variant):",r.id,n),this.deps.diagnose("DA-BREAK-NO-PLAYABLE-ASSET",`break ${r.id} has no playable variant (${n}); it will not begin.`,{breakId:r.id,reason:n}),this.deps.emit("aderror",{type:"aderror",timestamp:Date.now(),source:"ad",break:r,format:this.deps.effectiveFormatOf(r),error:new Error(`Break ${r.id} has no playable variant (${n})`)}),s!==this.state.sessionGeneration)return;return this.deps.breakScheduler.completeBreak(r.id),this.onBreakSkipped(r,"unsupported"),void this.deps.onBreakSettled?.()}this.deps.log("Break starting:",r.id,d.tuneIn?"(tune-in)":""),this.deps.breakTransitionTimer?.mark("into-break",r.id),this.breakBeginEmittedId=null,this.pendingAdBreakBegin=null;const o=this.state.heldImmediatePreRollId===r.id,p=this.deps.effectiveFormatOf(r),k=p===e.SINGLE||p===e.LSHAPE_AD,h=o&&k;o&&(this.state.heldImmediatePreRollId=null),this.deps.adBreakStatusTracker.setAdBreakStatusActive(r,void 0!==d.remainingSec?d.remainingSec:r.duration),h||this.emitAdBreakBegin(r,d),this.deps.manifestService.setActive(!0),this.deps.breakScheduler.claimChain(r.id);const l={onAdStart:(e,t,a,i,r)=>{this.deps.adBreakStatusTracker.onAdStarted(e,t,a,i),this.deps.emit("adbegin",{type:"adbegin",timestamp:Date.now(),break:e,format:this.deps.effectiveFormatOf(e),asset:t,adIndex:a,totalAds:i,...r?.adId?{adId:r.adId}:{},...r?.creativeId?{creativeId:r.creativeId}:{},...void 0!==r?.podPosition?{podPosition:r.podPosition}:{}})},onAdEnd:(e,t,a,i,r)=>{this.deps.adBreakStatusTracker.onAdEnded(e,a,i),a+1<i&&this.deps.breakTransitionTimer?.mark("ad-to-ad",e.id),this.deps.emit("adend",{type:"adend",timestamp:Date.now(),break:e,format:this.deps.effectiveFormatOf(e),asset:t,adIndex:a,totalAds:i,...r?.adId?{adId:r.adId}:{},...r?.creativeId?{creativeId:r.creativeId}:{}})},onAdError:(e,r,d)=>{this.flushPendingAdBreakBegin(),this.deps.diagnose("DA-AD-PLAYBACK-ERROR",d.message,{breakId:e.id,assetId:r?.id,adErrorCode:a(d),...d instanceof i?{vendorCode:d.vendorCode}:{},...t(d)}),this.deps.emit("aderror",{type:"aderror",timestamp:Date.now(),source:"ad",break:e,format:this.deps.effectiveFormatOf(e),...r?{asset:r}:{},error:d})},onAdTimeUpdate:(e,t,a,i)=>{this.deps.adBreakStatusTracker.onAdTimeUpdated(e,t,a,i),this.deps.emit("adtimeupdate",{type:"adtimeupdate",timestamp:Date.now(),break:e,format:this.deps.effectiveFormatOf(e),asset:t,currentTime:a,duration:i})},onAdWaiting:(e,t)=>{this.deps.adBreakStatusTracker.onAdPlaybackWaiting(),this.deps.emit("waiting",{type:"waiting",timestamp:Date.now(),source:"ad",break:e,asset:t})},onAdPlaying:(e,t)=>{this.deps.adBreakStatusTracker.onAdPlaybackPlaying(),this.deps.emit("playing",{type:"playing",timestamp:Date.now(),source:"ad",break:e,asset:t})},onBreakEnd:e=>{this.onBreakEnd(e)},onBreakCut:e=>{this.deps.cmcdAdReporter.onBreakCut(e.id)},onBreakEndedWithoutContentPause:()=>{this.onBreakEndedWithoutContentPause()},onChainedBreakBegin:e=>{this.onChainedBreakBegin(e)},onChainedBreakSkipped:e=>{s===this.state.sessionGeneration&&(this.deps.log("Chained break skipped (no playable variant):",e.id),this.deps.breakScheduler.completeBreak(e.id),this.onBreakSkipped(e,"unsupported"))},onContentResumeSeek:(e,t)=>{this.deps.breakScheduler.notifyResumeSeek(e,t)},onContentReloading:e=>{this.deps.breakScheduler.setContentReloading(e)}};h&&(this.pendingAdBreakBegin=()=>this.emitAdBreakBegin(r,d),l.onBreakVisible=e=>{this.deps.adBreakStatusTracker.setAdBreakVisible(e),this.flushPendingAdBreakBegin()}),await this.deps.adPlayerController.playBreak(r,l,{effectiveDurationSec:d.remainingSec,firstFrameGate:h})}onChainedBreakBegin(e){this.deps.log("Chained break starting:",e.id),this.deps.breakTransitionTimer?.mark("break-to-break",e.id),this.deps.breakScheduler.activateChainedBreak(e.id),this.deps.manifestService.setActive(!0),this.deps.adBreakStatusTracker.setAdBreakStatusActive(e,e.duration),this.emitAdBreakBegin(e)}onBreakEnd(e){this.deps.log("Break ended:",e.id),this.deps.breakTransitionTimer?.mark("out-of-break",e.id),this.deps.breakScheduler.completeBreak(e.id),this.deps.manifestService.setActive(!1),this.deps.adBreakStatusTracker.resetAdBreakStatus(),this.flushPendingAdBreakBegin(),this.deps.emit("adbreakend",{type:"adbreakend",timestamp:Date.now(),break:e,format:this.deps.effectiveFormatOf(e)}),this.deps.onBreakSettled?.()}onBreakEndedWithoutContentPause(){this.deps.breakTransitionTimer?.settle("out-of-break"),this.deps.emit("playing",{type:"playing",timestamp:Date.now(),source:"content"})}onBreakAborted(e){if(this.deps.adPlayerController.isAdPlaying()){const t=this.deps.adBreakStatusTracker.currentBreakElapsedSec();this.deps.log(`Early return — ending break '${e.id}' at ${t.toFixed(2)}s`),this.deps.cmcdAdReporter.onBreakAborted(e.id),this.deps.adPlayerController.abortBreak(t)}else this.deps.breakScheduler.completeBreak(e.id),this.deps.onBreakSettled?.()}reportAbandonedBreak(e){const t=this.deps.adBreakStatusTracker.activeBreak;if(!t)return;const a=this.deps.adBreakStatusTracker.currentAdIndex;this.deps.diagnose("DA-BREAK-ABANDONED",`Session torn down (${e}) while break ${t.id} was still in flight`+(null!==a?"; an ad began and will never end.":"."),{breakId:t.id,cause:e,phase:this.deps.adBreakStatusTracker.adBreakStatus.phase,unbalancedAdBegin:null!==a,...null!==a?{adIndex:a}:{},...null!==this.deps.adBreakStatusTracker.currentAdTotal?{totalAds:this.deps.adBreakStatusTracker.currentAdTotal}:{}})}}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PlayerAdapter } from '../interfaces/PlayerAdapter';
|
|
2
2
|
import { BreakManifest } from '../types/BreakManifest';
|
|
3
|
+
import { ExternalVendorConfigurationTracker } from '../services/ExternalVendorConfigurationTracker';
|
|
3
4
|
import { OptiViewAdsMode, SessionConfig, SsaiSessionConfig, StartSessionConfig } from '../types/OptiViewAdsConfig';
|
|
4
5
|
import { ManifestService } from '../services/ManifestService';
|
|
5
6
|
import { BreakScheduler } from '../services/BreakScheduler';
|
|
@@ -25,6 +26,7 @@ export interface SessionStarterDeps {
|
|
|
25
26
|
cmcdAdReporter: CmcdAdReporter;
|
|
26
27
|
lensReporter: LensReporter;
|
|
27
28
|
adBreakStatusTracker: AdBreakStatusTracker;
|
|
29
|
+
externalVendorConfigurationTracker: ExternalVendorConfigurationTracker;
|
|
28
30
|
emit: EmitEvent;
|
|
29
31
|
diagnose: Diagnose;
|
|
30
32
|
log: Log;
|
|
@@ -94,6 +96,8 @@ export declare class SessionStarter {
|
|
|
94
96
|
*/
|
|
95
97
|
private switchChannel;
|
|
96
98
|
private emitChannelChange;
|
|
99
|
+
private adoptExternalVendorConfigurations;
|
|
100
|
+
private diagnoseExternalVendorConfigurations;
|
|
97
101
|
private applySameModeChannelSwitch;
|
|
98
102
|
private switchToSteeredSsai;
|
|
99
103
|
private switchToSgai;
|
|
@@ -101,7 +105,8 @@ export declare class SessionStarter {
|
|
|
101
105
|
* Resolve the GAM stream identity from the manifest and open the IMA/DAI session. GAM failure
|
|
102
106
|
* is non-fatal: non-GAM breaks still schedule, only the GAM assets are skipped.
|
|
103
107
|
*/
|
|
104
|
-
startGamForManifest(manifest: BreakManifest, sessionParams: Record<string, string> | undefined, startStep: (step: string) => void): Promise<void>;
|
|
108
|
+
startGamForManifest(manifest: BreakManifest, sessionParams: Record<string, string> | undefined, startStep: (step: string) => void, generation?: number, initialStart?: boolean): Promise<void>;
|
|
109
|
+
private startResolvedGamSession;
|
|
105
110
|
/** SSAI session: create the IMA DAI stream, load the stitched master, wire timed-metadata forwarding. Throws on failure. */
|
|
106
111
|
startSsaiSession(config: SsaiSessionConfig, generation: number): Promise<void>;
|
|
107
112
|
/** Whether a startSession() begun at {@link generation} was invalidated by a later end/destroy/restart. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getPreRollDelay as e}from"../types/BreakManifest";import{manifestHasGamAssets as s,resolveGamVendorConfiguration as t}from"../services/resolveGamVendorConfiguration";import{SsaiController as i}from"../services/SsaiController";import{resolveUrlOrigin as a}from"../services/urlOrigin";import{filterSsaiClientBreaks as r,resolveStitchedStreamVendor as n,SsaiUnavailableError as o}from"../services/resolveDeliveryMode";import{detectDeviceType as d}from"../services/detectDeviceType";import{decideDeliveryMode as l,detectChannelSwitch as h,gamPodIdentityChanged as c}from"../services/channelSwitch";import{prepareWebRuntime as m}from"../services/webCompatibility";const p=1e4;function S(e){return"stitcherUrl"in e}function u(e){return"string"==typeof e&&""!==e.trim()}export class SessionStarter{constructor(e,s){this.state=e,this.deps=s}async startSession(s){if("ssai"===this.deps.mode){if(!S(s)||!u(s.stitcherUrl))throw new Error('[OptiViewAds] mode "ssai" requires a stitcherUrl in startSession().')}else if(S(s)||!u(s.manifestUrl))throw new Error("[OptiViewAds] startSession requires a manifestUrl (the full break-manifest URL).");this.state.sessionActive&&(this.deps.log("Ending previous session before starting new one"),this.deps.endSessionInternal("session-restart"));const t=this.state.sessionGeneration;this.state.sessionActive=!0;try{const e=m();e&&await e}catch(e){if(this.isStaleStart(t))return;throw this.state.sessionActive=!1,e}if(this.isStaleStart(t))return;if(this.deps.lensReporter.startSession(),S(s))return s.adInsertionType&&this.deps.diagnose("DA-INSERTION-TYPE-IGNORED-SSAI",`adInsertionType "${s.adInsertionType}" ignored in SSAI mode; the stitcher controls ad insertion.`,{adInsertionType:s.adInsertionType}),void await this.startSsaiSession(s,t);const i=s.manifestUrl;this.state.sessionConfig=s,this.state.manifestOrigin=a(i),this.deps.manifestService.setManifestUrl(i),this.deps.log("Session starting, manifest URL:",i);const r=Date.now(),n=e=>{this.deps.diagnose("DA-SESSION-STARTING",`Session start: ${e}`,{step:e,manifestUrl:i,elapsedMs:Date.now()-r})};n("begin");const o=s.assetParameters;let d;this.deps.adPlayerController.setSessionAssetParameters(o),this.deps.adPlayerController.setSessionAssetParameterMacros(s.assetParameterMacros),this.state.configSummary.gam&&(this.state.configSummary.gam={...this.state.configSummary.gam,hasAssetParameters:!!o}),n("manifest-fetch");try{d=await this.deps.manifestService.fetchManifest()}catch(e){if(this.isStaleStart(t))return;throw this.failSessionStart(e)}if(this.deps.cmcdAdReporter.onSessionStart(d),!this.isStaleStart(t))if(this.state.sessionManifest=d,"ssai"!==this.resolveSessionDeliveryMode(d))try{if(await this.startGamForManifest(d,o,n),this.isStaleStart(t))return;const a=s.adInsertionType;this.deps.adPlayerController.setBreakResumePolicy(a,d.timebase,this.deps.continueContentDuringBreak),this.deps.diagnose("DA-INSERTION-TYPE-RESOLVED",void 0===a?`Ad insertion type: unset — the manifest's resumeOffset drives the resume point (timebase: ${d.timebase})`:`Ad insertion type: ${a}, client-set (timebase: ${d.timebase})`,{adInsertionType:a??null,source:void 0===a?"unset":"client",timebase:d.timebase}),n("scheduling"),this.deps.breakScheduler.updateManifest(d),this.deps.pauseAdController.updateManifest(d),this.state.pauseAdTickInterval=setInterval(()=>this.deps.pauseAdController?.tick(),250);const r=(d.adStartDelay??0)>0?void 0:d.breaks.find(s=>0===e(s));r?(this.deps.adPlayerController.holdContentForPreRoll(r),this.state.heldImmediatePreRollId=r.id,this.state.heldPreRollArmed=!1,this.state.heldPreRollWaitStartedAt=Date.now(),this.contentIsReady()?this.armHeldImmediatePreRoll():this.state.heldPreRollArmInterval=setInterval(()=>{this.contentIsReady()?this.armHeldImmediatePreRoll():this.armHeldImmediatePreRollIfTimedOut()},250)):this.markPlaybackStartIfPlaying(),this.deps.startLivePushback(),this.startBreakScheduler(),this.startManifestPolling(),this.deps.diagnose("DA-SESSION-STARTED",`Session active for manifest ${i}`,{manifestUrl:i}),this.deps.log("Session active")}catch(e){if(this.isStaleStart(t))return;throw this.failSessionStart(e)}else await this.startSteeredSsaiSession(d,s,n)}markPlaybackStartIfPlaying(){this.deps.player.paused||this.deps.breakScheduler.markPlaybackStart()}contentIsReady(){return!Number.isNaN(this.deps.player.duration)||!this.deps.player.paused}clearHeldImmediatePreRollArmInterval(){this.state.heldPreRollArmInterval&&(clearInterval(this.state.heldPreRollArmInterval),this.state.heldPreRollArmInterval=null)}armHeldImmediatePreRoll(){this.state.heldImmediatePreRollId&&!this.state.heldPreRollArmed&&(this.clearHeldImmediatePreRollArmInterval(),this.state.heldPreRollArmed=!0,this.deps.breakScheduler.markPlaybackStart())}armHeldImmediatePreRollIfTimedOut(){if(!this.state.heldImmediatePreRollId||this.state.heldPreRollArmed)return;const e=this.state.heldPreRollWaitStartedAt;if(null===e||Date.now()-e<p)return;const s=this.state.heldImmediatePreRollId;this.armHeldImmediatePreRoll(),this.deps.diagnose("DA-PREROLL-CONTENT-WAIT-TIMEOUT","Pending pre-roll began after waiting 10000ms for content readiness.",{breakId:s,waitMs:p})}cancelHeldImmediatePreRollOnContentError(){const e=this.state.heldImmediatePreRollId;return!(!e||this.state.heldPreRollArmed)&&(this.clearHeldImmediatePreRollArmInterval(),this.deps.breakScheduler?.completeBreak(e),this.deps.adPlayerController?.releaseContentHold(),this.state.heldImmediatePreRollId=null,this.state.heldPreRollArmed=!1,this.state.heldPreRollWaitStartedAt=null,this.deps.diagnose("DA-PREROLL-CANCELLED-CONTENT-ERROR","A pending pre-roll was cancelled because the content failed to load before it could begin.",{breakId:e}),!0)}clearHeldImmediatePreRollArm(){this.clearHeldImmediatePreRollArmInterval(),this.state.heldImmediatePreRollId=null,this.state.heldPreRollArmed=!1,this.state.heldPreRollWaitStartedAt=null}failSessionStart(e){const s=e instanceof Error?e:new Error(String(e)),t=this.deps.manifestService?.takeLastFailure();return this.deps.diagnose("DA-MANIFEST-FETCH-FAILED",s.message,t?{...t}:void 0),this.state.sessionActive=!1,this.deps.cmcdAdReporter.onSessionEnd(),this.deps.lensReporter.endSession(),s}resolveSessionDeliveryMode(e,s="manifest"){const t=this.state.sessionDeliveryMode,i=l(e,d(),this.deps.hasExplicitMode?this.deps.mode:null,s);return null!==i.unknownMode&&this.deps.diagnose("DA-DELIVERY-MODE-UNKNOWN",`Delivery rule ${i.ruleIndex} carries unrecognized mode "${i.unknownMode}"; using sgai.`,{unknownMode:i.unknownMode,ruleIndex:i.ruleIndex}),this.deps.hasExplicitMode&&i.manifestMode!==i.mode&&this.deps.diagnose("DA-DELIVERY-MODE-OVERRIDDEN",`Manifest delivery rules resolve "${i.manifestMode}" but the explicit config mode "${i.mode}" takes precedence.`,{manifestMode:i.manifestMode,configuredMode:i.mode}),this.state.sessionDeliveryMode=i.mode,this.deps.diagnose("DA-DELIVERY-MODE-RESOLVED",`Delivery mode: ${i.mode}`,{mode:i.mode,ruleIndex:i.ruleIndex,source:i.source,..."channel-switch"===s?{previousMode:t}:{}}),i.mode}async startSteeredSsaiSession(e,s,t){const i=n(e.vendorConfiguration);if(!i){const e="Manifest selected ssai delivery but no vendor configuration provides a stitched stream (no gam entry with an assetKey).";throw this.deps.diagnose("DA-SSAI-UNAVAILABLE",e),this.deps.manifestService.reset(),this.state.sessionActive=!1,new o(e)}try{t("ssai-live-stream"),this.state.steeredSsaiActive=!0,this.state.ssaiController=this.createSsaiController(i.networkCode),await this.state.ssaiController.startSteered(i,s.assetParameters,s.assetParameterMacros),t("scheduling");const a=r(e);this.deps.adPlayerController.setBreakResumePolicy(s.adInsertionType,e.timebase,!1),this.deps.breakScheduler.updateManifest(a),this.deps.pauseAdController.updateManifest(a),this.state.pauseAdTickInterval=setInterval(()=>this.deps.pauseAdController?.tick(),250),this.markPlaybackStartIfPlaying(),this.deps.startLivePushback(),this.startBreakScheduler(),this.startManifestPolling(),this.deps.diagnose("DA-SESSION-STARTED",`SSAI session active (manifest-steered) for ${s.manifestUrl}`,{manifestUrl:s.manifestUrl}),this.deps.log("SSAI session active (manifest-steered)")}catch(e){const s=e instanceof Error?e:new Error(String(e));throw this.deps.diagnose("DA-SSAI-SESSION-FAILED",s.message),this.state.steeredSsaiActive=!1,this.deps.manifestService.reset(),this.state.sessionActive=!1,s}}createSsaiController(e){return new i(this.deps.player,{gam:this.state.steeredSsaiOptions?.streamActivityMonitorId?{streamActivityMonitorId:this.state.steeredSsaiOptions.streamActivityMonitorId}:{},ssai:{networkCode:e},maxBitrate:this.state.steeredSsaiOptions?.maxBitrate,autoplay:this.state.steeredSsaiOptions?.autoplay,debug:this.deps.debug},{emit:(e,s)=>this.deps.emit(e,s),diagnose:(e,s,t)=>this.deps.diagnose(e,s,t),log:(...e)=>this.deps.log(...e)})}startBreakScheduler(){this.deps.breakScheduler.start((e,s)=>{this.deps.breakLifecycle.onBreakStart(e,s)},e=>!this.deps.adPlayerController.isAdPlaying()&&(this.deps.adPlayerController.preload(e).catch(s=>{this.deps.diagnose("DA-PRELOAD-FAILED",s instanceof Error?s.message:String(s),{breakId:e.id})}),!0),(e,s,t)=>{this.deps.adBreakStatusTracker.onBreakWarning(e,s,t)},e=>{this.deps.breakLifecycle.onBreakAborted(e)})}startManifestPolling(){this.deps.manifestService.startPolling(e=>{if(!this.state.sessionActive)return;const s=this.deps.notedManifestBreakIds(e);this.deps.diagnose("DA-MANIFEST-POLLED","Manifest polled",{breaks:e.breaks.length,newBreakIds:s,pollingIntervalSeconds:this.deps.manifestService.currentPollingIntervalSeconds});const t=this.state.sessionManifest,i=t?h(t,e):null;if(this.state.pendingChannelSwitch||i&&this.deps.breakScheduler.getActiveBreak())return this.state.pendingChannelSwitch=e,void this.deps.log("Channel switch deferred until the active break ends");i?this.switchChannel(e,i):this.applyManifestUpdate(e)},e=>{this.state.sessionActive&&this.deps.diagnose("DA-MANIFEST-POLL-FAILED",e.message)})}applyPendingChannelSwitch(){if(!this.state.sessionActive||!this.state.pendingChannelSwitch)return;const e=this.state.pendingChannelSwitch;this.state.pendingChannelSwitch=null;const s=h(this.state.sessionManifest,e);s?this.switchChannel(e,s):this.applyManifestUpdate(e)}applyManifestUpdate(e){this.diagnoseIgnoredDeliveryModeChange(e);const s=t(e);this.state.steeredSsaiActive?this.state.ssaiController?.setManifestAssetParameters(s.ssai?.assetParameters):this.deps.adPlayerController.setManifestAssetParameters(s.sgaiAssetParameters);const i=this.state.steeredSsaiActive?r(e):e;this.deps.breakScheduler.updateManifest(i),this.deps.pauseAdController.updateManifest(i)}diagnoseIgnoredDeliveryModeChange(e){if(!this.state.sessionDeliveryMode)return;const s=l(e,d(),null,"manifest");s.manifestMode!==this.state.sessionDeliveryMode&&this.deps.diagnose("DA-DELIVERY-MODE-CHANGE-IGNORED",`Polled manifest resolves delivery mode "${s.manifestMode}" but "${this.state.sessionDeliveryMode}" is pinned for this session.`,{polledMode:s.manifestMode,pinnedMode:this.state.sessionDeliveryMode})}async switchChannel(e,s){if(this.state.channelSwitchInFlight)return;const t=this.state.sessionConfig,i=this.state.sessionManifest,a={previousChannelId:s.previousChannelId,channelId:s.channelId,reason:s.reason,manifestUrl:t.manifestUrl};this.deps.diagnose("DA-MANIFEST-CHANNEL-CHANGED",`Manifest channel changed (${s.reason}): ${s.previousChannelId??"none"} -> ${s.channelId??"none"}`,a),this.state.sessionManifest=e,this.state.channelSwitchInFlight=!0;const r=this.state.sessionGeneration,n=this.state.sessionDeliveryMode??"sgai";try{let s=this.resolveSessionDeliveryMode(e,"channel-switch");if(this.deps.cmcdAdReporter.onSessionEnd(),this.deps.cmcdAdReporter.onSessionStart(e),this.deps.lensReporter.endSession(),this.deps.lensReporter.startSession(),"ssai"===s&&"sgai"===n){const a=await this.switchToSteeredSsai(e,t);if(this.isStaleStart(r))return;a||(s="sgai",this.state.sessionDeliveryMode="sgai",await this.applySameModeChannelSwitch(i,e,t,r))}else"sgai"===s&&"ssai"===n?await this.switchToSgai(e,t,r):await this.applySameModeChannelSwitch(i,e,t,r);if(this.isStaleStart(r))return}finally{this.state.channelSwitchInFlight=!1}this.deps.startLivePushback(),this.emitChannelChange({...a,previousDeliveryMode:n,deliveryMode:this.state.sessionDeliveryMode??n})}emitChannelChange(e){this.deps.emit("adchannelchange",{type:"adchannelchange",timestamp:Date.now(),...e})}async applySameModeChannelSwitch(e,s,i,a){const n=this.state.steeredSsaiActive,o=n?r(s):s;if(this.deps.breakScheduler.resetForChannelSwitch(o),this.deps.pauseAdController.updateManifest(o),this.deps.adPlayerController.setBreakResumePolicy(i.adInsertionType,s.timebase,this.deps.continueContentDuringBreak),!n&&c(e,s)){const e=this.deps.adPlayerController.updatedAssetParameters,t=this.deps.adPlayerController.sessionAssetParameterMacros;if(this.deps.adPlayerController.endGamSession(),this.deps.adPlayerController.setSessionAssetParameters(i.assetParameters),this.deps.adPlayerController.setSessionAssetParameterMacros(t),await this.startGamForManifest(s,i.assetParameters,e=>{this.deps.diagnose("DA-SESSION-STARTING",`Channel switch: ${e}`,{step:e,manifestUrl:i.manifestUrl})}),this.isStaleStart(a))return;e&&this.deps.adPlayerController.updateAssetParameters(e)}else if(n){const e=t(s);this.state.ssaiController?.setManifestAssetParameters(e.ssai?.assetParameters)}else{const e=t(s);this.deps.adPlayerController.setManifestAssetParameters(e.sgaiAssetParameters)}}async switchToSteeredSsai(e,s){const t=n(e.vendorConfiguration);if(!t)return this.deps.diagnose("DA-SSAI-UNAVAILABLE","Channel switch resolved ssai delivery but no vendor configuration provides a stitched stream; the session stays in sgai.",{manifestUrl:s.manifestUrl,previousMode:"sgai"}),!1;const i=this.deps.adPlayerController,a=i.updatedAssetParameters,o=i.sessionAssetParameterMacros;i.stopActiveBreak(),i.releaseContentHold(),i.endGamSession(),i.setSessionAssetParameters(s.assetParameters),i.setSessionAssetParameterMacros(o),a&&i.updateAssetParameters(a);const d=this.createSsaiController(t.networkCode);this.state.ssaiController=d,this.state.steeredSsaiActive=!0,this.deps.diagnose("DA-SESSION-STARTING","Channel switch: ssai-live-stream",{step:"ssai-live-stream",manifestUrl:s.manifestUrl});try{await d.startSteered(t,s.assetParameters,o),a&&d.updateAssetParameters(a);const n=r(e);return this.deps.breakScheduler.resetForChannelSwitch(n),this.deps.pauseAdController.updateManifest(n),i.setBreakResumePolicy(s.adInsertionType,e.timebase,!1),!0}catch(e){const s=e instanceof Error?e.message:String(e);return this.deps.diagnose("DA-SSAI-SESSION-FAILED",s),d.stop(),delete this.state.ssaiController,this.state.steeredSsaiActive=!1,!1}}async switchToSgai(e,s,t){const i=this.state.ssaiController?.sessionAssetParameterMacros;this.state.ssaiController?.stop(),delete this.state.ssaiController,this.state.steeredSsaiActive=!1,this.deps.breakScheduler.resetForChannelSwitch(e),this.deps.pauseAdController.updateManifest(e);const a=this.deps.adPlayerController;a.setBreakResumePolicy(s.adInsertionType,e.timebase,this.deps.continueContentDuringBreak);const r=a.updatedAssetParameters;a.endGamSession(),a.setSessionAssetParameters(s.assetParameters),a.setSessionAssetParameterMacros(i??s.assetParameterMacros),await this.startGamForManifest(e,s.assetParameters,e=>{this.deps.diagnose("DA-SESSION-STARTING",`Channel switch: ${e}`,{step:e,manifestUrl:s.manifestUrl})}),this.isStaleStart(t)||r&&a.updateAssetParameters(r)}async startGamForManifest(e,i,a){const r=t(e);if(this.deps.adPlayerController.setManifestAssetParameters(r.sgaiAssetParameters),r.unknownTypes.length>0&&this.deps.diagnose("DA-VENDOR-CONFIG-UNKNOWN-TYPE",`Ignored ${r.unknownTypes.length} vendorConfiguration `+(1===r.unknownTypes.length?"entry":"entries")+" with unrecognised type: "+`${r.unknownTypes.join(", ")}.`,{types:r.unknownTypes}),this.deps.adPlayerController.isGamEnabled())if(r.identity){this.deps.diagnose("DA-GAM-CONFIG-RESOLVED",`GAM session identity: network ${r.identity.networkCode}, custom asset ${r.identity.customAssetKey}`,{networkCode:r.identity.networkCode,customAssetKey:r.identity.customAssetKey,channelId:e.channelId,duplicateEntriesIgnored:r.duplicateGam});try{a("gam-init"),await this.deps.adPlayerController.startGamSession(r.identity,i),this.deps.log("GAM session started")}catch(e){this.deps.diagnose("DA-GAM-SESSION-FAILED",e instanceof Error?e.message:String(e))}}else s(e)&&this.deps.diagnose("DA-GAM-CONFIG-MISSING",'The break manifest carries GAM pod assets but no usable "gam" vendorConfiguration entry; those assets will be skipped.',{reason:r.reason});else s(e)&&this.deps.diagnose("DA-GAM-CONFIG-MISSING","The break manifest carries GAM pod assets but GAM is disabled for this session (gam.enabled === false); those assets will be skipped.",{reason:"gam-disabled"})}async startSsaiSession(e,s){try{if(this.state.stitcherOrigin=a(e.stitcherUrl),this.state.configSummary.gam&&(this.state.configSummary.gam={...this.state.configSummary.gam,hasAssetParameters:!!e.assetParameters}),await this.state.ssaiController.start(e),this.isStaleStart(s))return;this.deps.diagnose("DA-SESSION-STARTED",`SSAI session active for ${e.stitcherUrl}`,{stitcherUrl:e.stitcherUrl}),this.deps.startLivePushback(),this.deps.log("SSAI session active")}catch(e){if(this.isStaleStart(s))return;const t=e instanceof Error?e:new Error(String(e));throw this.deps.diagnose("DA-SSAI-SESSION-FAILED",t.message),this.state.sessionActive=!1,this.deps.cmcdAdReporter.onSessionEnd(),this.deps.lensReporter.endSession(),t}}isStaleStart(e){return e!==this.state.sessionGeneration&&(this.deps.log("Session start aborted — the session ended or was replaced while starting"),!0)}}
|
|
1
|
+
import{getPreRollDelay as e}from"../types/BreakManifest";import{manifestHasGamAssets as s,resolveGamVendorConfiguration as t}from"../services/resolveGamVendorConfiguration";import{resolveExternalVendorConfigurations as i}from"../services/resolveExternalVendorConfigurations";import{SsaiController as a}from"../services/SsaiController";import{resolveUrlOrigin as r}from"../services/urlOrigin";import{filterSsaiClientBreaks as n,resolveStitchedStreamVendor as o,SsaiUnavailableError as d}from"../services/resolveDeliveryMode";import{detectDeviceProfile as l}from"../services/detectDeviceType";import{decideDeliveryMode as h,detectChannelSwitch as c,gamPodIdentityChanged as p}from"../services/channelSwitch";import{prepareWebRuntime as m}from"../services/webCompatibility";const S=1e4;function u(e){return"stitcherUrl"in e}function f(e){return"string"==typeof e&&""!==e.trim()}export class SessionStarter{constructor(e,s){this.state=e,this.deps=s}async startSession(s){if("ssai"===this.deps.mode){if(!u(s)||!f(s.stitcherUrl))throw new Error('[OptiViewAds] mode "ssai" requires a stitcherUrl in startSession().')}else if(u(s)||!f(s.manifestUrl))throw new Error("[OptiViewAds] startSession requires a manifestUrl (the full break-manifest URL).");this.state.sessionActive&&(this.deps.log("Ending previous session before starting new one"),this.deps.endSessionInternal("session-restart"));const t=this.state.sessionGeneration;this.state.sessionActive=!0,this.state.adStartDelayElapsed=!1;try{const e=m();e&&await e}catch(e){if(this.isStaleStart(t))return;throw this.state.sessionActive=!1,e}if(this.isStaleStart(t))return;if(this.deps.lensReporter.startSession(),u(s))return s.adInsertionType&&this.deps.diagnose("DA-INSERTION-TYPE-IGNORED-SSAI",`adInsertionType "${s.adInsertionType}" ignored in SSAI mode; the stitcher controls ad insertion.`,{adInsertionType:s.adInsertionType}),void await this.startSsaiSession(s,t);const i=s.manifestUrl;this.state.sessionConfig=s,this.state.manifestOrigin=r(i),this.deps.manifestService.setManifestUrl(i),this.deps.log("Session starting, manifest URL:",i);const a=Date.now(),n=e=>{this.deps.diagnose("DA-SESSION-STARTING",`Session start: ${e}`,{step:e,manifestUrl:i,elapsedMs:Date.now()-a})};n("begin");const o=s.assetParameters;let d;this.deps.adPlayerController.setSessionAssetParameters(o),this.deps.adPlayerController.setSessionAssetParameterMacros(s.assetParameterMacros),this.state.configSummary.gam&&(this.state.configSummary.gam={...this.state.configSummary.gam,hasAssetParameters:!!o}),n("manifest-fetch");try{d=await this.deps.manifestService.fetchManifest()}catch(e){if(this.isStaleStart(t))return;throw this.failSessionStart(e)}if(this.deps.cmcdAdReporter.onSessionStart(d),!this.isStaleStart(t))if(this.state.sessionManifest=d,this.adoptExternalVendorConfigurations(d),"ssai"!==this.resolveSessionDeliveryMode(d))try{if(await this.startGamForManifest(d,o,n,t,!0),this.isStaleStart(t))return;const a=s.adInsertionType;this.deps.adPlayerController.setBreakResumePolicy(a,d.timebase,this.deps.continueContentDuringBreak),this.deps.diagnose("DA-INSERTION-TYPE-RESOLVED",void 0===a?`Ad insertion type: unset — the manifest's resumeOffset drives the resume point (timebase: ${d.timebase})`:`Ad insertion type: ${a}, client-set (timebase: ${d.timebase})`,{adInsertionType:a??null,source:void 0===a?"unset":"client",timebase:d.timebase}),n("scheduling"),this.deps.breakScheduler.updateManifest(d),this.deps.pauseAdController.updateManifest(d),this.state.pauseAdTickInterval=setInterval(()=>this.deps.pauseAdController?.tick(),250);const r=(d.adStartDelay??0)>0?void 0:d.breaks.find(s=>0===e(s));r?(this.deps.adPlayerController.holdContentForPreRoll(r),this.state.heldImmediatePreRollId=r.id,this.state.heldPreRollArmed=!1,this.state.heldPreRollWaitStartedAt=Date.now(),this.contentIsReady()?this.armHeldImmediatePreRoll():this.state.heldPreRollArmInterval=setInterval(()=>{this.contentIsReady()?this.armHeldImmediatePreRoll():this.armHeldImmediatePreRollIfTimedOut()},250)):this.markPlaybackStartIfPlaying(),this.deps.startLivePushback(),this.startBreakScheduler(),this.startManifestPolling(),this.deps.diagnose("DA-SESSION-STARTED",`Session active for manifest ${i}`,{manifestUrl:i}),this.deps.log("Session active")}catch(e){if(this.isStaleStart(t))return;throw this.failSessionStart(e)}else await this.startSteeredSsaiSession(d,s,n)}markPlaybackStartIfPlaying(){this.deps.player.paused||this.deps.breakScheduler.markPlaybackStart()}contentIsReady(){return!Number.isNaN(this.deps.player.duration)||!this.deps.player.paused}clearHeldImmediatePreRollArmInterval(){this.state.heldPreRollArmInterval&&(clearInterval(this.state.heldPreRollArmInterval),this.state.heldPreRollArmInterval=null)}armHeldImmediatePreRoll(){this.state.heldImmediatePreRollId&&!this.state.heldPreRollArmed&&(this.clearHeldImmediatePreRollArmInterval(),this.state.heldPreRollArmed=!0,this.deps.breakScheduler.markPlaybackStart())}armHeldImmediatePreRollIfTimedOut(){if(!this.state.heldImmediatePreRollId||this.state.heldPreRollArmed)return;const e=this.state.heldPreRollWaitStartedAt;if(null===e||Date.now()-e<S)return;const s=this.state.heldImmediatePreRollId;this.armHeldImmediatePreRoll(),this.deps.diagnose("DA-PREROLL-CONTENT-WAIT-TIMEOUT","Pending pre-roll began after waiting 10000ms for content readiness.",{breakId:s,waitMs:S})}cancelHeldImmediatePreRollOnContentError(){const e=this.state.heldImmediatePreRollId;return!(!e||this.state.heldPreRollArmed)&&(this.clearHeldImmediatePreRollArmInterval(),this.deps.breakScheduler?.completeBreak(e),this.deps.adPlayerController?.releaseContentHold(),this.state.heldImmediatePreRollId=null,this.state.heldPreRollArmed=!1,this.state.heldPreRollWaitStartedAt=null,this.deps.diagnose("DA-PREROLL-CANCELLED-CONTENT-ERROR","A pending pre-roll was cancelled because the content failed to load before it could begin.",{breakId:e}),!0)}clearHeldImmediatePreRollArm(){this.clearHeldImmediatePreRollArmInterval(),this.state.heldImmediatePreRollId=null,this.state.heldPreRollArmed=!1,this.state.heldPreRollWaitStartedAt=null}failSessionStart(e){const s=e instanceof Error?e:new Error(String(e)),t=this.deps.manifestService?.takeLastFailure();return this.deps.diagnose("DA-MANIFEST-FETCH-FAILED",s.message,t?{...t}:void 0),this.state.sessionActive=!1,this.deps.cmcdAdReporter.onSessionEnd(),this.deps.lensReporter.endSession(),s}resolveSessionDeliveryMode(e,s="manifest"){const t=this.state.sessionDeliveryMode,i=h(e,l(),this.deps.hasExplicitMode?this.deps.mode:null,s);null!==i.unknownMode&&this.deps.diagnose("DA-DELIVERY-MODE-UNKNOWN",`Delivery rule ${i.ruleIndex} carries unrecognized mode "${i.unknownMode}"; using sgai.`,{unknownMode:i.unknownMode,ruleIndex:i.ruleIndex});for(const e of i.targetingIssues)this.deps.diagnose(e.code,`Targeting ${e.field} was rejected.`,{field:e.field,...void 0===e.value?{}:{value:e.value}});return this.deps.hasExplicitMode&&i.manifestMode!==i.mode&&this.deps.diagnose("DA-DELIVERY-MODE-OVERRIDDEN",`Manifest delivery rules resolve "${i.manifestMode}" but the explicit config mode "${i.mode}" takes precedence.`,{manifestMode:i.manifestMode,configuredMode:i.mode}),this.state.sessionDeliveryMode=i.mode,this.deps.diagnose("DA-DELIVERY-MODE-RESOLVED",`Delivery mode: ${i.mode}`,{mode:i.mode,ruleIndex:i.ruleIndex,source:i.source,deviceProfile:l(),..."channel-switch"===s?{previousMode:t}:{}}),i.mode}async startSteeredSsaiSession(e,s,t){const i=o(e.vendorConfiguration);if(!i){const e="Manifest selected ssai delivery but no vendor configuration provides a stitched stream (no gam entry with an assetKey).";throw this.deps.diagnose("DA-SSAI-UNAVAILABLE",e),this.deps.manifestService.reset(),this.state.sessionActive=!1,new d(e)}try{t("ssai-live-stream"),this.state.steeredSsaiActive=!0,this.state.ssaiController=this.createSsaiController(i.networkCode),await this.state.ssaiController.startSteered(i,s.assetParameters,s.assetParameterMacros),t("scheduling");const a=n(e);this.deps.adPlayerController.setBreakResumePolicy(s.adInsertionType,e.timebase,!1),this.deps.breakScheduler.updateManifest(a),this.deps.pauseAdController.updateManifest(a),this.state.pauseAdTickInterval=setInterval(()=>this.deps.pauseAdController?.tick(),250),this.markPlaybackStartIfPlaying(),this.deps.startLivePushback(),this.startBreakScheduler(),this.startManifestPolling(),this.deps.diagnose("DA-SESSION-STARTED",`SSAI session active (manifest-steered) for ${s.manifestUrl}`,{manifestUrl:s.manifestUrl}),this.deps.log("SSAI session active (manifest-steered)")}catch(e){const s=e instanceof Error?e:new Error(String(e));throw this.deps.diagnose("DA-SSAI-SESSION-FAILED",s.message),this.state.steeredSsaiActive=!1,this.deps.manifestService.reset(),this.state.sessionActive=!1,s}}createSsaiController(e){return new a(this.deps.player,{gam:this.state.steeredSsaiOptions?.streamActivityMonitorId?{streamActivityMonitorId:this.state.steeredSsaiOptions.streamActivityMonitorId}:{},ssai:{networkCode:e},maxBitrate:this.state.steeredSsaiOptions?.maxBitrate,autoplay:this.state.steeredSsaiOptions?.autoplay,debug:this.deps.debug},{emit:(e,s)=>this.deps.emit(e,s),diagnose:(e,s,t)=>this.deps.diagnose(e,s,t),log:(...e)=>this.deps.log(...e)})}startBreakScheduler(){this.deps.breakScheduler.start((e,s)=>{this.deps.breakLifecycle.onBreakStart(e,s)},e=>!this.deps.adPlayerController.isAdPlaying()&&(this.deps.adPlayerController.preload(e).catch(s=>{this.deps.diagnose("DA-PRELOAD-FAILED",s instanceof Error?s.message:String(s),{breakId:e.id})}),!0),(e,s,t)=>{this.deps.adBreakStatusTracker.onBreakWarning(e,s,t)},e=>{this.deps.breakLifecycle.onBreakAborted(e)},(e,s)=>this.deps.breakLifecycle.onBreakSkipped(e,s))}startManifestPolling(){this.deps.manifestService.startPolling(e=>{if(!this.state.sessionActive)return;const s=this.deps.notedManifestBreakIds(e);this.deps.diagnose("DA-MANIFEST-POLLED","Manifest polled",{breaks:e.breaks.length,newBreakIds:s,pollingIntervalSeconds:this.deps.manifestService.currentPollingIntervalSeconds});const t=this.state.sessionManifest,i=t?c(t,e):null;if(this.state.pendingChannelSwitch||i&&this.deps.breakScheduler.getActiveBreak())return this.state.pendingChannelSwitch=e,void this.deps.log("Channel switch deferred until the active break ends");i?this.switchChannel(e,i):this.applyManifestUpdate(e)},e=>{this.state.sessionActive&&this.deps.diagnose("DA-MANIFEST-POLL-FAILED",e.message)})}applyPendingChannelSwitch(){if(!this.state.sessionActive||!this.state.pendingChannelSwitch)return;const e=this.state.pendingChannelSwitch;this.state.pendingChannelSwitch=null;const s=c(this.state.sessionManifest,e);s?this.switchChannel(e,s):this.applyManifestUpdate(e)}applyManifestUpdate(e){if(!this.state.sessionActive)return;this.adoptExternalVendorConfigurations(e),this.diagnoseIgnoredDeliveryModeChange(e);const s=t(e);this.state.steeredSsaiActive?this.state.ssaiController?.setManifestAssetParameters(s.ssai?.assetParameters):this.deps.adPlayerController.setManifestAssetParameters(s.sgaiAssetParameters);const i=this.state.steeredSsaiActive?n(e):e;this.deps.breakScheduler.updateManifest(i),this.deps.pauseAdController.updateManifest(i)}diagnoseIgnoredDeliveryModeChange(e){if(!this.state.sessionDeliveryMode)return;const s=h(e,l(),null,"manifest");s.manifestMode!==this.state.sessionDeliveryMode&&this.deps.diagnose("DA-DELIVERY-MODE-CHANGE-IGNORED",`Polled manifest resolves delivery mode "${s.manifestMode}" but "${this.state.sessionDeliveryMode}" is pinned for this session.`,{polledMode:s.manifestMode,pinnedMode:this.state.sessionDeliveryMode})}async switchChannel(e,s){if(this.state.channelSwitchInFlight)return;const t=this.state.sessionConfig,i=this.state.sessionManifest,a={previousChannelId:s.previousChannelId,channelId:s.channelId,reason:s.reason,manifestUrl:t.manifestUrl};this.deps.diagnose("DA-MANIFEST-CHANNEL-CHANGED",`Manifest channel changed (${s.reason}): ${s.previousChannelId??"none"} -> ${s.channelId??"none"}`,a),this.state.sessionManifest=e,this.state.channelSwitchInFlight=!0;const r=this.state.sessionGeneration,n=this.state.sessionDeliveryMode??"sgai";try{let s=this.resolveSessionDeliveryMode(e,"channel-switch");if(this.deps.cmcdAdReporter.onSessionEnd(),this.deps.cmcdAdReporter.onSessionStart(e),this.deps.lensReporter.endSession(),this.deps.lensReporter.startSession(),"ssai"===s&&"sgai"===n){const a=await this.switchToSteeredSsai(e,t);if(this.isStaleStart(r))return;a||(s="sgai",this.state.sessionDeliveryMode="sgai",await this.applySameModeChannelSwitch(i,e,t,r))}else"sgai"===s&&"ssai"===n?await this.switchToSgai(e,t,r):await this.applySameModeChannelSwitch(i,e,t,r);if(this.isStaleStart(r))return}finally{this.state.channelSwitchInFlight=!1}this.adoptExternalVendorConfigurations(e),this.deps.startLivePushback(),this.emitChannelChange({...a,previousDeliveryMode:n,deliveryMode:this.state.sessionDeliveryMode??n})}emitChannelChange(e){this.deps.emit("adchannelchange",{type:"adchannelchange",timestamp:Date.now(),...e})}adoptExternalVendorConfigurations(e){this.deps.externalVendorConfigurationTracker.adopt(e)}diagnoseExternalVendorConfigurations(e){const s=i(e);s.invalidCount>0&&this.deps.diagnose("DA-EXTERNAL-VENDOR-INVALID",`Ignored ${s.invalidCount} invalid external vendorConfiguration `+(1===s.invalidCount?"entry":"entries")+".",{count:s.invalidCount}),s.duplicateProviders.length>0&&this.deps.diagnose("DA-EXTERNAL-VENDOR-DUPLICATE",`Ignored duplicate external vendorConfiguration entries for providers: ${s.duplicateProviders.join(", ")}.`,{providers:s.duplicateProviders})}async applySameModeChannelSwitch(e,s,i,a){const r=this.state.steeredSsaiActive,o=r?n(s):s;if(this.deps.breakScheduler.resetForChannelSwitch(o),this.deps.pauseAdController.updateManifest(o),this.deps.adPlayerController.setBreakResumePolicy(i.adInsertionType,s.timebase,this.deps.continueContentDuringBreak),!r&&p(e,s)){const e=this.deps.adPlayerController.updatedAssetParameters,t=this.deps.adPlayerController.sessionAssetParameterMacros;if(this.deps.adPlayerController.endGamSession(),this.deps.adPlayerController.setSessionAssetParameters(i.assetParameters),this.deps.adPlayerController.setSessionAssetParameterMacros(t),await this.startGamForManifest(s,i.assetParameters,e=>{this.deps.diagnose("DA-SESSION-STARTING",`Channel switch: ${e}`,{step:e,manifestUrl:i.manifestUrl})},a),this.isStaleStart(a))return;e&&this.deps.adPlayerController.updateAssetParameters(e)}else if(r){const e=t(s);this.state.ssaiController?.setManifestAssetParameters(e.ssai?.assetParameters)}else{const e=t(s);this.deps.adPlayerController.setManifestAssetParameters(e.sgaiAssetParameters)}}async switchToSteeredSsai(e,s){const t=o(e.vendorConfiguration);if(!t)return this.deps.diagnose("DA-SSAI-UNAVAILABLE","Channel switch resolved ssai delivery but no vendor configuration provides a stitched stream; the session stays in sgai.",{manifestUrl:s.manifestUrl,previousMode:"sgai"}),!1;const i=this.deps.adPlayerController,a=i.updatedAssetParameters,r=i.sessionAssetParameterMacros;i.stopActiveBreak(),i.releaseContentHold(),i.endGamSession(),i.setSessionAssetParameters(s.assetParameters),i.setSessionAssetParameterMacros(r),a&&i.updateAssetParameters(a);const d=this.createSsaiController(t.networkCode);this.state.ssaiController=d,this.state.steeredSsaiActive=!0,this.deps.diagnose("DA-SESSION-STARTING","Channel switch: ssai-live-stream",{step:"ssai-live-stream",manifestUrl:s.manifestUrl});try{await d.startSteered(t,s.assetParameters,r),a&&d.updateAssetParameters(a);const o=n(e);return this.deps.breakScheduler.resetForChannelSwitch(o),this.deps.pauseAdController.updateManifest(o),i.setBreakResumePolicy(s.adInsertionType,e.timebase,!1),!0}catch(e){const s=e instanceof Error?e.message:String(e);return this.deps.diagnose("DA-SSAI-SESSION-FAILED",s),d.stop(),delete this.state.ssaiController,this.state.steeredSsaiActive=!1,!1}}async switchToSgai(e,s,t){const i=this.state.ssaiController?.sessionAssetParameterMacros;this.state.ssaiController?.stop(),delete this.state.ssaiController,this.state.steeredSsaiActive=!1,this.deps.breakScheduler.resetForChannelSwitch(e),this.deps.pauseAdController.updateManifest(e);const a=this.deps.adPlayerController;a.setBreakResumePolicy(s.adInsertionType,e.timebase,this.deps.continueContentDuringBreak);const r=a.updatedAssetParameters;a.endGamSession(),a.setSessionAssetParameters(s.assetParameters),a.setSessionAssetParameterMacros(i??s.assetParameterMacros),await this.startGamForManifest(e,s.assetParameters,e=>{this.deps.diagnose("DA-SESSION-STARTING",`Channel switch: ${e}`,{step:e,manifestUrl:s.manifestUrl})},t),this.isStaleStart(t)||r&&a.updateAssetParameters(r)}async startGamForManifest(e,i,a,r=this.state.sessionGeneration,n=!1){const o=t(e);if(this.deps.adPlayerController.setManifestAssetParameters(o.sgaiAssetParameters),o.unknownTypes.length>0&&this.deps.diagnose("DA-VENDOR-CONFIG-UNKNOWN-TYPE",`Ignored ${o.unknownTypes.length} vendorConfiguration `+(1===o.unknownTypes.length?"entry":"entries")+" with unrecognised type: "+`${o.unknownTypes.join(", ")}.`,{types:o.unknownTypes}),this.diagnoseExternalVendorConfigurations(e),!this.deps.adPlayerController.isGamEnabled())return void(s(e)&&this.deps.diagnose("DA-GAM-CONFIG-MISSING","The break manifest carries GAM pod assets but GAM is disabled for this session (gam.enabled === false); those assets will be skipped.",{reason:"gam-disabled"}));if(!o.identity)return void(s(e)&&this.deps.diagnose("DA-GAM-CONFIG-MISSING",'The break manifest carries GAM pod assets but no usable "gam" vendorConfiguration entry; those assets will be skipped.',{reason:o.reason}));this.deps.diagnose("DA-GAM-CONFIG-RESOLVED",`GAM session identity: network ${o.identity.networkCode}, custom asset ${o.identity.customAssetKey}`,{networkCode:o.identity.networkCode,customAssetKey:o.identity.customAssetKey,channelId:e.channelId,duplicateEntriesIgnored:o.duplicateGam});const d=e.adStartDelay??0;if(d>0&&!this.state.adStartDelayElapsed&&(n||this.deps.breakScheduler.isAdStartDelayActive()))return this.deps.breakScheduler.holdBreakStarts(),this.deps.diagnose("DA-GAM-START-DEFERRED",`GAM session start deferred until ${d} seconds of content have played.`,{adStartDelaySec:d}),void this.deps.breakScheduler.setOnAdStartDelayElapsed(()=>{if(this.isStaleStart(r)||!this.state.sessionActive)return;this.state.adStartDelayElapsed=!0;const s=this.state.sessionManifest??e,n=t(s).identity;n?(this.deps.adPlayerController.setManifestAssetParameters(t(s).sgaiAssetParameters),this.startResolvedGamSession(n,i,a,r,!0)):this.deps.breakScheduler.releaseBreakStarts()});this.state.adStartDelayElapsed=!0,await this.startResolvedGamSession(o.identity,i,a,r)}async startResolvedGamSession(e,s,t,i,a=!1){try{if(this.isStaleStart(i)||!this.state.sessionActive)return;t("gam-init"),await this.deps.adPlayerController.startGamSession(e,s),this.deps.log("GAM session started")}catch(e){this.deps.diagnose("DA-GAM-SESSION-FAILED",e instanceof Error?e.message:String(e))}finally{a&&!this.isStaleStart(i)&&this.state.sessionActive&&this.deps.breakScheduler.releaseBreakStarts()}}async startSsaiSession(e,s){try{if(this.state.stitcherOrigin=r(e.stitcherUrl),this.state.configSummary.gam&&(this.state.configSummary.gam={...this.state.configSummary.gam,hasAssetParameters:!!e.assetParameters}),await this.state.ssaiController.start(e),this.isStaleStart(s))return;this.deps.diagnose("DA-SESSION-STARTED",`SSAI session active for ${e.stitcherUrl}`,{stitcherUrl:e.stitcherUrl}),this.deps.startLivePushback(),this.deps.log("SSAI session active")}catch(e){if(this.isStaleStart(s))return;const t=e instanceof Error?e:new Error(String(e));throw this.deps.diagnose("DA-SSAI-SESSION-FAILED",t.message),this.state.sessionActive=!1,this.deps.cmcdAdReporter.onSessionEnd(),this.deps.lensReporter.endSession(),t}}isStaleStart(e){return e!==this.state.sessionGeneration&&(this.deps.log("Session start aborted — the session ended or was replaced while starting"),!0)}}
|
|
@@ -11,6 +11,7 @@ export declare class SessionState {
|
|
|
11
11
|
* "replaced" — the new session sets it back to true before the stale fetch resolves.
|
|
12
12
|
*/
|
|
13
13
|
sessionGeneration: number;
|
|
14
|
+
adStartDelayElapsed: boolean;
|
|
14
15
|
sessionDeliveryMode: OptiViewAdsMode | null;
|
|
15
16
|
steeredSsaiActive: boolean;
|
|
16
17
|
steeredSsaiOptions: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export class SessionState{constructor(){this.sessionActive=!1,this.sessionGeneration=0,this.sessionDeliveryMode=null,this.steeredSsaiActive=!1,this.steeredSsaiOptions=null,this.pauseAdTickInterval=null,this.heldPreRollArmInterval=null,this.manifestOrigin=null,this.stitcherOrigin=null,this.heldImmediatePreRollId=null,this.heldPreRollArmed=!1,this.heldPreRollWaitStartedAt=null,this.snapbackSeekInFlight=!1,this.sessionConfig=null,this.sessionManifest=null,this.channelSwitchInFlight=!1,this.pendingChannelSwitch=null}clearSessionIdentity(){this.sessionDeliveryMode=null,this.sessionManifest=null,this.channelSwitchInFlight=!1,this.pendingChannelSwitch=null}}
|
|
1
|
+
export class SessionState{constructor(){this.sessionActive=!1,this.sessionGeneration=0,this.adStartDelayElapsed=!1,this.sessionDeliveryMode=null,this.steeredSsaiActive=!1,this.steeredSsaiOptions=null,this.pauseAdTickInterval=null,this.heldPreRollArmInterval=null,this.manifestOrigin=null,this.stitcherOrigin=null,this.heldImmediatePreRollId=null,this.heldPreRollArmed=!1,this.heldPreRollWaitStartedAt=null,this.snapbackSeekInFlight=!1,this.sessionConfig=null,this.sessionManifest=null,this.channelSwitchInFlight=!1,this.pendingChannelSwitch=null}clearSessionIdentity(){this.sessionDeliveryMode=null,this.sessionManifest=null,this.channelSwitchInFlight=!1,this.pendingChannelSwitch=null}}
|
|
@@ -54,8 +54,13 @@ export interface GamVendorConfiguration extends VendorConfigurationBase {
|
|
|
54
54
|
sgai?: GamSgaiConfiguration[];
|
|
55
55
|
ssai?: GamSsaiConfiguration[];
|
|
56
56
|
}
|
|
57
|
+
export interface ExternalVendorConfigurationEntry extends VendorConfigurationBase {
|
|
58
|
+
type: 'external';
|
|
59
|
+
provider: string;
|
|
60
|
+
assetParameters: Record<string, string>;
|
|
61
|
+
}
|
|
57
62
|
/** Known vendor configuration entries, kept open to unrecognized vendors from newer manifests. @category Break Manifests & Ad Formats */
|
|
58
|
-
export type VendorConfiguration = GamVendorConfiguration | VendorConfigurationBase;
|
|
63
|
+
export type VendorConfiguration = GamVendorConfiguration | ExternalVendorConfigurationEntry | VendorConfigurationBase;
|
|
59
64
|
/** Type guard: narrows a {@link VendorConfiguration} to a {@link GamVendorConfiguration}. */
|
|
60
65
|
export declare function isGamVendorConfiguration(entry: VendorConfiguration): entry is GamVendorConfiguration;
|
|
61
66
|
/** The root Break Manifest structure. @category Break Manifests & Ad Formats */
|
|
@@ -167,14 +172,47 @@ export declare enum BreakFormat {
|
|
|
167
172
|
}
|
|
168
173
|
/** Device type for targeting. @category Break Manifests & Ad Formats */
|
|
169
174
|
export declare enum DeviceType {
|
|
175
|
+
CONSOLE = "console",
|
|
170
176
|
DESKTOP = "desktop",
|
|
171
177
|
MOBILE = "mobile",
|
|
172
178
|
TABLET = "tablet",
|
|
173
179
|
TV = "tv"
|
|
174
180
|
}
|
|
181
|
+
/** Platforms supported by manifest targeting (manifest spec v1.7.0). */
|
|
182
|
+
export declare enum Platform {
|
|
183
|
+
WEB = "web",
|
|
184
|
+
ANDROID = "android",
|
|
185
|
+
IOS = "ios",
|
|
186
|
+
TVOS = "tvos",
|
|
187
|
+
ROKU = "roku"
|
|
188
|
+
}
|
|
189
|
+
/** Operating systems supported by manifest targeting (manifest spec v1.8.0). */
|
|
190
|
+
export declare enum Os {
|
|
191
|
+
ANDROID = "android",
|
|
192
|
+
CHROMEOS = "chromeos",
|
|
193
|
+
IOS = "ios",
|
|
194
|
+
IPADOS = "ipados",
|
|
195
|
+
LINUX = "linux",
|
|
196
|
+
MACOS = "macos",
|
|
197
|
+
ROKUOS = "rokuos",
|
|
198
|
+
TIZEN = "tizen",
|
|
199
|
+
TVOS = "tvos",
|
|
200
|
+
VIZIO = "vizio",
|
|
201
|
+
WEBOS = "webos",
|
|
202
|
+
WINDOWS = "windows",
|
|
203
|
+
XBOX = "xbox"
|
|
204
|
+
}
|
|
205
|
+
/** Inclusive operating-system version bounds; each bound is dot-separated decimal integers. */
|
|
206
|
+
export interface OsVersionRange {
|
|
207
|
+
min?: string;
|
|
208
|
+
max?: string;
|
|
209
|
+
}
|
|
175
210
|
/** Targeting criteria for break variants. @category Break Manifests & Ad Formats */
|
|
176
211
|
export interface Targeting {
|
|
177
212
|
deviceType?: DeviceType;
|
|
213
|
+
platform?: Platform;
|
|
214
|
+
os?: Os;
|
|
215
|
+
osVersion?: OsVersionRange;
|
|
178
216
|
}
|
|
179
217
|
/** Base fields for all break variants. @category Break Manifests & Ad Formats */
|
|
180
218
|
export interface BaseBreakVariant {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export var Timebase;!function(e){e.WALLCLOCK="wallclock",e.PTS="pts",e.MEDIATIME="mediatime"}(Timebase||(Timebase={}));export function isGamVendorConfiguration(e){return"gam"===e.type}export var DeliveryMode;!function(e){e.SGAI="sgai",e.SSAI="ssai"}(DeliveryMode||(DeliveryMode={}));export var BreakEvent;!function(e){e.START="start",e.PAUSE="pause",e.END="end"}(BreakEvent||(BreakEvent={}));export var BreakFormat;!function(e){e.SINGLE="single",e.DOUBLE="double",e.LSHAPE_AD="lshape_ad",e.LSHAPE_CONTENT="lshape_content",e.OVERLAY="overlay"}(BreakFormat||(BreakFormat={}));export var DeviceType;!function(e){e.DESKTOP="desktop",e.MOBILE="mobile",e.TABLET="tablet",e.TV="tv"}(DeviceType||(DeviceType={}));export var AssetType;!function(e){e.STATIC="static",e.VAST="vast",e.VENDOR="vendor"}(AssetType||(AssetType={}));export var MediaType;!function(e){e.VIDEO="video",e.IMAGE="image"}(MediaType||(MediaType={}));export var Vendor;!function(e){e.GAM="gam"}(Vendor||(Vendor={}));export function isEventTrigger(e){return"object"==typeof e&&null!==e&&"event"===e.type}export function getBreakEvent(e){return"pre"===e.position?BreakEvent.START:isEventTrigger(e.start)?e.start.event:null}export function isPauseBreak(e){return getBreakEvent(e)===BreakEvent.PAUSE}export function getPreRollDelay(e){return getBreakEvent(e)!==BreakEvent.START?null:"pre"===e.position?e.delay??0:isEventTrigger(e.start)?e.start.delay??0:0}export function isPostRollBreak(e){return getBreakEvent(e)===BreakEvent.END}export function getPostRollDelay(e){return isEventTrigger(e.start)&&e.start.event===BreakEvent.END?e.start.delay??0:null}export function isStaticAsset(e){return e.type===AssetType.STATIC}export function isVastAsset(e){return e.type===AssetType.VAST}export function isVendorAsset(e){return e.type===AssetType.VENDOR}
|
|
1
|
+
export var Timebase;!function(e){e.WALLCLOCK="wallclock",e.PTS="pts",e.MEDIATIME="mediatime"}(Timebase||(Timebase={}));export function isGamVendorConfiguration(e){return"gam"===e.type}export var DeliveryMode;!function(e){e.SGAI="sgai",e.SSAI="ssai"}(DeliveryMode||(DeliveryMode={}));export var BreakEvent;!function(e){e.START="start",e.PAUSE="pause",e.END="end"}(BreakEvent||(BreakEvent={}));export var BreakFormat;!function(e){e.SINGLE="single",e.DOUBLE="double",e.LSHAPE_AD="lshape_ad",e.LSHAPE_CONTENT="lshape_content",e.OVERLAY="overlay"}(BreakFormat||(BreakFormat={}));export var DeviceType;!function(e){e.CONSOLE="console",e.DESKTOP="desktop",e.MOBILE="mobile",e.TABLET="tablet",e.TV="tv"}(DeviceType||(DeviceType={}));export var Platform;!function(e){e.WEB="web",e.ANDROID="android",e.IOS="ios",e.TVOS="tvos",e.ROKU="roku"}(Platform||(Platform={}));export var Os;!function(e){e.ANDROID="android",e.CHROMEOS="chromeos",e.IOS="ios",e.IPADOS="ipados",e.LINUX="linux",e.MACOS="macos",e.ROKUOS="rokuos",e.TIZEN="tizen",e.TVOS="tvos",e.VIZIO="vizio",e.WEBOS="webos",e.WINDOWS="windows",e.XBOX="xbox"}(Os||(Os={}));export var AssetType;!function(e){e.STATIC="static",e.VAST="vast",e.VENDOR="vendor"}(AssetType||(AssetType={}));export var MediaType;!function(e){e.VIDEO="video",e.IMAGE="image"}(MediaType||(MediaType={}));export var Vendor;!function(e){e.GAM="gam"}(Vendor||(Vendor={}));export function isEventTrigger(e){return"object"==typeof e&&null!==e&&"event"===e.type}export function getBreakEvent(e){return"pre"===e.position?BreakEvent.START:isEventTrigger(e.start)?e.start.event:null}export function isPauseBreak(e){return getBreakEvent(e)===BreakEvent.PAUSE}export function getPreRollDelay(e){return getBreakEvent(e)!==BreakEvent.START?null:"pre"===e.position?e.delay??0:isEventTrigger(e.start)?e.start.delay??0:0}export function isPostRollBreak(e){return getBreakEvent(e)===BreakEvent.END}export function getPostRollDelay(e){return isEventTrigger(e.start)&&e.start.event===BreakEvent.END?e.start.delay??0:null}export function isStaticAsset(e){return e.type===AssetType.STATIC}export function isVastAsset(e){return e.type===AssetType.VAST}export function isVendorAsset(e){return e.type===AssetType.VENDOR}
|
package/dist/types/Events.d.ts
CHANGED
|
@@ -7,6 +7,14 @@ import type { OptiViewAdsMode } from './OptiViewAdsConfig';
|
|
|
7
7
|
* - `active`: a break is currently playing.
|
|
8
8
|
* @category Events */
|
|
9
9
|
export type AdBreakPhase = 'idle' | 'upcoming' | 'active' | 'complete';
|
|
10
|
+
/** Why a scheduled ad break was refused before it began (`adbreakskipped` event). @category Events */
|
|
11
|
+
export type AdBreakSkipReason = 'late' | 'not-ready' | 'preparation-failed' | 'unsupported' | 'overlap' | 'start-delay' | 'removed' | 'insufficient-remaining' | 'resource-limit';
|
|
12
|
+
export interface AdBreakSkippedEvent extends OptiViewAdsEvent {
|
|
13
|
+
type: 'adbreakskipped';
|
|
14
|
+
break: Break;
|
|
15
|
+
reason: AdBreakSkipReason;
|
|
16
|
+
format?: BreakFormat | undefined;
|
|
17
|
+
}
|
|
10
18
|
/** Playback-gated snapshot of an ad break for UI countdowns (`adbreakstatus` event, `sdk.getAdBreakStatus()`). @category Events */
|
|
11
19
|
export interface AdBreakStatus {
|
|
12
20
|
/** Current lifecycle phase of the ad break. */
|
|
@@ -31,7 +39,7 @@ export interface AdBreakStatus {
|
|
|
31
39
|
warningSec?: number | undefined;
|
|
32
40
|
}
|
|
33
41
|
/** Event types emitted by the OptiViewAds SDK. @category Events */
|
|
34
|
-
export type OptiViewAdsEventType = 'adbreakbegin' | 'adbreakend' | 'adbegin' | 'adend' | 'aderror' | 'adfirstquartile' | 'admidpoint' | 'adthirdquartile' | 'adtimeupdate' | 'adbreakstatus' | 'adclick' | 'waiting' | 'playing' | 'volumechange' | 'adchannelchange';
|
|
42
|
+
export type OptiViewAdsEventType = 'adbreakbegin' | 'adbreakend' | 'adbreakskipped' | 'adbegin' | 'adend' | 'aderror' | 'adfirstquartile' | 'admidpoint' | 'adthirdquartile' | 'adtimeupdate' | 'adbreakstatus' | 'adclick' | 'waiting' | 'playing' | 'volumechange' | 'adchannelchange' | 'externalvendorconfigurationchange';
|
|
35
43
|
/** Which player a playback event originated from. @category Events */
|
|
36
44
|
export type PlaybackSource = 'ad' | 'content';
|
|
37
45
|
/** Base event interface. @category Events */
|
|
@@ -223,10 +231,16 @@ export interface AdChannelChangeEvent extends OptiViewAdsEvent {
|
|
|
223
231
|
/** Delivery mode in effect after the switch. */
|
|
224
232
|
deliveryMode: OptiViewAdsMode;
|
|
225
233
|
}
|
|
234
|
+
/** An external provider's manifest parameter template was added, changed, or removed. @category Events */
|
|
235
|
+
export interface ExternalVendorConfigurationChangeEvent extends OptiViewAdsEvent {
|
|
236
|
+
type: 'externalvendorconfigurationchange';
|
|
237
|
+
provider: string;
|
|
238
|
+
}
|
|
226
239
|
/** Union type of all SDK events. @category Events */
|
|
227
240
|
export type OptiViewAdsEventMap = {
|
|
228
241
|
adbreakbegin: AdBreakBeginEvent;
|
|
229
242
|
adbreakend: AdBreakEndEvent;
|
|
243
|
+
adbreakskipped: AdBreakSkippedEvent;
|
|
230
244
|
adbegin: AdBeginEvent;
|
|
231
245
|
adend: AdEndEvent;
|
|
232
246
|
aderror: AdErrorEvent;
|
|
@@ -240,6 +254,7 @@ export type OptiViewAdsEventMap = {
|
|
|
240
254
|
playing: PlayingEvent;
|
|
241
255
|
volumechange: VolumeChangeEvent;
|
|
242
256
|
adchannelchange: AdChannelChangeEvent;
|
|
257
|
+
externalvendorconfigurationchange: ExternalVendorConfigurationChangeEvent;
|
|
243
258
|
};
|
|
244
259
|
/** Event handler type. @category Events */
|
|
245
260
|
export type OptiViewAdsEventHandler<T extends OptiViewAdsEventType> = (event: OptiViewAdsEventMap[T]) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{};
|
|
@@ -427,7 +427,8 @@ export interface SessionConfig {
|
|
|
427
427
|
* is unchanged.
|
|
428
428
|
* Callbacks are evaluated per ad request and cleared when the session ends.
|
|
429
429
|
* Session-scoped parameters are sent to IMA DAI with
|
|
430
|
-
* built-in and customer macros resolved; break-duration macros are
|
|
430
|
+
* built-in and customer macros resolved; break-duration macros stay literal and are
|
|
431
|
+
* reported as `DA-ASSET-MACRO-UNKNOWN`.
|
|
431
432
|
*
|
|
432
433
|
* @see OPTIVIEW_ASSET_PARAMETER_MACROS
|
|
433
434
|
*/
|