@dolby-optiview/ads-sdk-core 1.0.0-beta.6 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -0
- package/dist/OptiViewAds.d.ts +1 -0
- package/dist/OptiViewAds.js +1 -1
- package/dist/diagnostics/DiagnosticEvent.d.ts +2 -0
- package/dist/diagnostics/playbackErrorContext.d.ts +0 -17
- package/dist/diagnostics/playbackErrorContext.js +1 -1
- package/dist/diagnostics/recordEventTimeline.d.ts +3 -0
- package/dist/diagnostics/recordEventTimeline.js +1 -0
- package/dist/generated/diagnosticCodes.d.ts +111 -1
- 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/parseId3Geob.d.ts +26 -5
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -1
- package/dist/interfaces/PlayerAdapter.d.ts +45 -1
- package/dist/internal/index.d.ts +1 -1
- package/dist/internal/index.js +1 -1
- package/dist/server/index.d.ts +3 -1
- package/dist/server/index.js +1 -1
- package/dist/services/AdPlayerController.d.ts +11 -9
- package/dist/services/AdPlayerController.js +1 -1
- package/dist/services/BreakScheduler.d.ts +5 -2
- package/dist/services/BreakScheduler.js +1 -1
- package/dist/services/CmcdAdReporter.d.ts +33 -3
- package/dist/services/CmcdAdReporter.js +1 -1
- package/dist/services/GamPodAdTracker.d.ts +15 -2
- package/dist/services/GamPodAdTracker.js +1 -1
- package/dist/services/GamStreamManager.js +1 -1
- package/dist/services/LensReporter.d.ts +3 -1
- package/dist/services/LensReporter.js +1 -1
- package/dist/services/LiveStartPushbackController.d.ts +36 -0
- package/dist/services/LiveStartPushbackController.js +1 -0
- package/dist/services/MetadataCueTracker.d.ts +15 -0
- package/dist/services/MetadataCueTracker.js +1 -1
- package/dist/services/SsaiController.js +1 -1
- package/dist/services/StitcherUrlBuilder.js +1 -1
- package/dist/services/VastAdManager.js +1 -1
- package/dist/services/adPlayer/AdPlayerEvents.js +1 -1
- package/dist/services/adPlayer/AdPlayerState.d.ts +14 -0
- package/dist/services/adPlayer/AdPlayerState.js +1 -1
- package/dist/services/adPlayer/AdPreloader.d.ts +9 -1
- package/dist/services/adPlayer/AdPreloader.js +1 -1
- package/dist/services/adPlayer/AdStage.d.ts +6 -0
- package/dist/services/adPlayer/AdStage.js +1 -1
- package/dist/services/adPlayer/AssetParameterResolver.js +1 -1
- package/dist/services/adPlayer/AssetPlayback.d.ts +15 -1
- package/dist/services/adPlayer/AssetPlayback.js +1 -1
- package/dist/services/adPlayer/ContentRecovery.d.ts +32 -0
- package/dist/services/adPlayer/ContentRecovery.js +1 -0
- package/dist/services/adPlayer/ContentResumeCoordinator.d.ts +46 -0
- package/dist/services/adPlayer/ContentResumeCoordinator.js +1 -1
- package/dist/services/adPlayer/GamPodBridge.d.ts +7 -0
- package/dist/services/adPlayer/GamPodBridge.js +1 -1
- package/dist/services/adPlayer/PlaybackCutoff.d.ts +3 -0
- package/dist/services/adPlayer/PlaybackCutoff.js +1 -0
- package/dist/services/adPlayer/PreparedPresentation.d.ts +32 -0
- package/dist/services/adPlayer/PreparedPresentation.js +1 -0
- package/dist/services/adPlayer/SharedElementBreakPlayer.d.ts +15 -1
- package/dist/services/adPlayer/SharedElementBreakPlayer.js +1 -1
- package/dist/services/adPlayer/classifyMediaError.d.ts +9 -0
- package/dist/services/adPlayer/classifyMediaError.js +1 -0
- package/dist/services/adPlayer/liveEdge.d.ts +29 -0
- package/dist/services/adPlayer/liveEdge.js +1 -1
- package/dist/services/anvatoCueRuntime.d.ts +7 -0
- package/dist/services/anvatoCueRuntime.js +1 -1
- package/dist/services/classifyImaAdError.d.ts +6 -0
- package/dist/services/classifyImaAdError.js +1 -0
- package/dist/services/detectContentRecovery.d.ts +12 -0
- package/dist/services/detectContentRecovery.js +1 -0
- package/dist/services/detectInsertionMode.js +1 -1
- package/dist/services/fetchWithTimeout.js +1 -1
- package/dist/services/html5ImaErrorNames.d.ts +2 -0
- package/dist/services/html5ImaErrorNames.js +1 -0
- package/dist/services/lensBackend.d.ts +1 -1
- package/dist/services/resolveGamVendorConfiguration.js +1 -1
- package/dist/services/resolveLiveStartPushback.d.ts +1 -0
- package/dist/services/resolveLiveStartPushback.js +1 -0
- package/dist/services/resolvedModeDiagnostics.d.ts +18 -0
- package/dist/services/resolvedModeDiagnostics.js +1 -0
- package/dist/services/runtimeObject.d.ts +2 -0
- package/dist/services/runtimeObject.js +1 -0
- package/dist/services/webCompatibility.d.ts +4 -0
- package/dist/services/webCompatibility.js +1 -0
- package/dist/services/webRuntime.d.ts +8 -0
- package/dist/services/webRuntime.js +1 -0
- package/dist/services/xhrWithTimeout.d.ts +1 -0
- package/dist/services/xhrWithTimeout.js +1 -0
- package/dist/session/AdBreakStatusTracker.d.ts +6 -3
- package/dist/session/AdBreakStatusTracker.js +1 -1
- package/dist/session/BreakLifecycle.js +1 -1
- package/dist/session/SessionStarter.d.ts +1 -0
- package/dist/session/SessionStarter.js +1 -1
- package/dist/types/AdError.d.ts +12 -0
- package/dist/types/AdError.js +1 -0
- package/dist/types/Events.d.ts +1 -1
- package/dist/types/OptiViewAdsConfig.d.ts +42 -5
- package/dist/types/OptiViewAdsConfig.js +1 -1
- package/dist/types/VendorAdError.d.ts +6 -5
- package/dist/types/VendorAdError.js +1 -1
- package/dist/types/compatibility-modules.d.ts +4 -0
- package/dist/types/compatibility-modules.js +1 -0
- package/dist/vendor/lens-sdk/THIRD-PARTY-NOTICES.txt +1 -1
- package/dist/vendor/lens-sdk/index.d.ts +1 -1
- package/dist/vendor/lens-sdk/index.js +1 -1
- package/dist/vendor/lens-sdk/lens-core-uGZfZpQy.js +1 -0
- package/dist/vendor/lens-sdk/lens.d.ts +2 -0
- package/dist/vendor/lens-sdk/teardown.d.ts +13 -0
- package/dist/vendor/lens-sdk/transport.d.ts +11 -2
- package/dist/vendor/lens-sdk/types.d.ts +56 -5
- package/dist/vendor/lens-sdk/validation.d.ts +4 -1
- package/package.json +6 -2
- package/dist/vendor/lens-sdk/lens-core-Q5lbQGMC.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{LensEventType as
|
|
1
|
+
import{LensEventType as e,LensToken as t}from"../vendor/lens-sdk/index.js";import{AssetType as i,BreakFormat as s,getBreakEvent as a}from"../types/BreakManifest";import{adErrorCode as d}from"../types/AdError";import{VendorAdError as r}from"../types/VendorAdError";import{SDK_VERSION as n}from"../generated/version";const h={[s.SINGLE]:"s",[s.DOUBLE]:"d",[s.LSHAPE_AD]:"la",[s.LSHAPE_CONTENT]:"lc",[s.OVERLAY]:"o"},o={[i.STATIC]:"s",[i.VAST]:"va",[i.VENDOR]:"ve"};function l(e){const t=a(e);if(null!==t)return t;const{start:i}=e;return"number"==typeof i?String(Math.round(1e3*i)):"string"==typeof i?i:i.event}function c(e){return o[e]??e}export class CmcdAdReporter{constructor(e,t){this.getHandle=e,this.log=t,this.sessionKeys={},this.activeBreakId=null,this.breakBeginTimestamp=null,this.breakAvailableMs=null,this.breakRequestedMs=null,this.firstAdReported=!1,this.breakFilledMs=0,this.breakWatchedMs=0,this.activeAdKeys=null,this.activeAdCompanion=null,this.activeAdAssetId=null,this.activeAdIsVendor=!1,this.activeAdBaseSec=0,this.breakLastTimeSec=0,this.pendingAdStart=null,this.activeAdWatchedSec=0,this.activeAdDeclaredSec=null,this.activeAdIsVast=!1,this.activeAdResolvedSec=null,this.skipRequestedBreakId=null,this.abortedBreakId=null,this.cutBreakId=null,this.erroredAssetId=null,this.finalizedBreakId=null}onSessionStart(e){this.sessionKeys={adv:n,admv:e.version,...e.organizationId?{adoid:e.organizationId}:{},...e.channelId?{adcid:e.channelId}:{},...e.eventId?{adeid:e.eventId}:{}},this.updateHeartbeat()}onSessionEnd(){this.finalizeActiveBreak(),this.sessionKeys={},this.resetBreakState(),this.guard("setHeartbeatPayload",e=>e.setHeartbeatPayload())}finalizeActiveBreak(){if(null===this.activeBreakId)return;const e=this.activeBreakId;this.emitPendingAdStart(null),null!==this.activeAdKeys&&this.emitAdEnd(this.activeAdKeys,this.activeAdCompanion,"a"),this.emitBreakEnd(e),this.finalizedBreakId=e}onSkipRequested(e){this.skipRequestedBreakId=e}onBreakAborted(e){this.abortedBreakId=e}onBreakCut(e){this.cutBreakId=e}onEvent(e){switch(e.type){case"adbreakbegin":this.onBreakBegin(e);break;case"adbegin":this.onAdBegin(e);break;case"adtimeupdate":{const t=e;this.breakLastTimeSec=Math.max(this.breakLastTimeSec,t.currentTime);null!==this.pendingAdStart&&(t.asset.id===this.pendingAdStart.assetId||this.pendingAdStart.isVendor&&t.break.id===this.activeBreakId)&&t.currentTime>(this.pendingAdStart?.isVendor?this.pendingAdStart.baseSec:0)&&null!==this.breakBeginTimestamp&&this.emitPendingAdStart(t.timestamp-this.breakBeginTimestamp);if(t.asset.id===this.activeAdAssetId||this.activeAdIsVendor&&t.break.id===this.activeBreakId){const e=t.currentTime-this.activeAdBaseSec;this.activeAdWatchedSec=Math.max(this.activeAdWatchedSec,e),this.activeAdIsVast&&Number.isFinite(t.duration)&&t.duration>0&&(this.activeAdResolvedSec=t.duration)}break}case"adend":this.onAdEnd(e);break;case"adbreakend":this.onBreakEnd(e);break;case"adfirstquartile":case"admidpoint":case"adthirdquartile":this.onMilestone(e);break;case"adclick":this.onClick(e);break;case"aderror":this.onAdError(e)}}onBreakBegin(i){this.resetBreakState(),this.finalizedBreakId=null,this.activeBreakId=i.break.id,this.breakBeginTimestamp=i.timestamp;const s=Math.round(1e3*i.remainingSec),a=this.requestedPlayableMs(i.break,i.format,s)??s;this.breakAvailableMs=s,this.breakRequestedMs=a,this.guard("abs",d=>{return d.emit(e.AD_BREAK_START,{custom:{...this.sessionKeys,brid:i.break.id,brst:l(i.break),brmd:Math.round(1e3*i.break.duration),brad:s,brrd:a,...i.format?{brf:new t((r=i.format,h[r]??r))}:{}}});var r}),this.updateHeartbeat()}onAdBegin(e){this.emitPendingAdStart(null);const s=e.asset,a=s.interaction?.clickThrough,d=!this.firstAdReported&&null!==this.breakBeginTimestamp;this.firstAdReported=!0;const r={brid:e.break.id,adasid:s.id,adid:e.adId??s.id,...void 0!==e.podPosition?{adpos:String(e.podPosition)}:{},...void 0!==s.duration?{adasd:Math.round(1e3*s.duration)}:{},adast:new t(c(s.type)),...a?{adcl:!0}:{},...e.creativeId?{adgcrid:e.creativeId}:{},...e.adId&&"string"==typeof s.uri&&"vendor"===s.type?{adgpid:s.uri}:{}};this.activeAdKeys=r,this.activeAdCompanion=s.companion?{id:s.companion.id,parentAssetId:s.id}:null,this.activeAdAssetId=s.id,this.activeAdIsVendor=s.type===i.VENDOR,this.activeAdBaseSec=this.activeAdIsVendor?this.breakLastTimeSec:0,this.activeAdWatchedSec=0,this.activeAdDeclaredSec=s.duration??null,this.activeAdIsVast=s.type===i.VAST,this.activeAdResolvedSec=null;const n={...this.sessionKeys,...r},h=s.companion?{...this.sessionKeys,brid:e.break.id,adasid:s.companion.id,adid:s.companion.id,adast:new t(c(s.companion.type)),adcomp:!0,adpasid:s.id}:null;d?this.pendingAdStart={assetId:s.id,custom:n,companionCustom:h,isVendor:this.activeAdIsVendor,baseSec:this.activeAdBaseSec}:this.emitAdStart(n,h),this.updateHeartbeat()}emitAdStart(t,i){this.guard("as",i=>i.emit(e.AD_START,{custom:t})),i&&this.guard("as",t=>t.emit(e.AD_START,{custom:i}))}emitPendingAdStart(e){const t=this.pendingAdStart;if(!t)return;this.pendingAdStart=null;const i=null!==e?{...t.custom,brttf:e}:t.custom;this.emitAdStart(i,t.companionCustom)}onAdEnd(e){if(e.break.id===this.finalizedBreakId)return;this.emitPendingAdStart(null);const t=e.asset,i=this.adEndReason(e),s=this.activeAdKeys??{brid:e.break.id,adasid:t.id,adid:e.adId??t.id},a=t.companion?{id:t.companion.id,parentAssetId:t.id}:null;this.emitAdEnd(s,a,i)}emitAdEnd(i,s,a){const d=this.activeAdFilledSec(),r=null!==d?Math.round(1e3*d):null,n=Math.round(1e3*this.activeAdWatchedSec),h=null!==r?Math.min(n,r):n;"s"===a&&this.guard("sk",t=>t.emit(e.AD_SKIP,{custom:{...this.sessionKeys,...i}})),this.guard("ae",s=>s.emit(e.AD_END,{custom:{...this.sessionKeys,...i,ader:new t(a),adwd:h}})),s&&this.guard("ae",d=>d.emit(e.AD_END,{custom:{...this.sessionKeys,brid:i.brid,adasid:s.id,adid:s.id,adcomp:!0,adpasid:s.parentAssetId,ader:new t(a)}})),this.breakWatchedMs+=h,this.breakFilledMs+=null!==r?r:h,this.activeAdKeys=null,this.activeAdCompanion=null,this.activeAdAssetId=null,this.activeAdIsVendor=!1,this.activeAdBaseSec=0,this.activeAdWatchedSec=0,this.activeAdDeclaredSec=null,this.activeAdIsVast=!1,this.activeAdResolvedSec=null,this.erroredAssetId===i.adasid&&(this.erroredAssetId=null),this.updateHeartbeat()}onBreakEnd(e){if(e.break.id!==this.finalizedBreakId){if(this.emitPendingAdStart(null),null!==this.breakAvailableMs){const t=this.requestedPlayableMs(e.break,e.format,this.breakAvailableMs);null!==t&&(this.breakRequestedMs=t)}this.emitBreakEnd(e.break.id)}}emitBreakEnd(t){const i=this.breakAvailableMs,s=null!==this.breakRequestedMs&&null!==i?Math.min(this.breakRequestedMs,i):this.breakRequestedMs,a=null!==s?Math.min(this.breakFilledMs,s):this.breakFilledMs,d=Math.min(this.breakWatchedMs,a);this.guard("abe",r=>r.emit(e.AD_BREAK_END,{custom:{...this.sessionKeys,brid:t,...null!==i?{brad:i}:{},...null!==s?{brrd:s}:{},brfd:a,brwd:d}})),this.resetBreakState(),this.updateHeartbeat()}onMilestone(e){this.emitPendingAdStart(null),this.emitCustomWithAdContext(e.type,e.break,e.asset)}onClick(e){this.emitPendingAdStart(null),this.emitCustomWithAdContext("adclick",e.break,e.asset)}onAdError(e){"ad"===e.source&&(this.emitPendingAdStart(null),e.asset&&(this.erroredAssetId=e.asset.id),this.guard("aderror",t=>t.emitCustom("aderror",{custom:{...this.sessionKeys,adec:e.asset?d(e.error):"DA-BREAK-NO-PLAYABLE-ASSET",...e.error instanceof r?{adevc:e.error.vendorCode}:{},...e.break&&e.asset?this.adContextKeys(e.break,e.asset):{...e.break?{brid:e.break.id}:{},...e.asset?{adasid:e.asset.id,adid:e.asset.id}:{}}}})))}emitCustomWithAdContext(e,t,i){this.guard(e,s=>s.emitCustom(e,{custom:{...this.sessionKeys,...this.adContextKeys(t,i)}}))}activeAdFilledSec(){const e=this.activeAdDeclaredSec,t=this.activeAdResolvedSec;return null===t?e:null===e?t:Math.min(t,e)}adContextKeys(e,t){return(t.id===this.activeAdAssetId||this.activeAdIsVendor&&e.id===this.activeBreakId)&&null!==this.activeAdKeys?{...this.activeAdKeys}:{brid:e.id,adasid:t.id,...void 0!==this.activeAdKeys?.adid?{adid:this.activeAdKeys.adid}:{}}}adEndReason(e){return this.skipRequestedBreakId===e.break.id?(this.skipRequestedBreakId=null,"s"):this.erroredAssetId===e.asset.id?"e":this.abortedBreakId===e.break.id?"a":this.cutBreakId===e.break.id?(this.cutBreakId=null,"a"):"c"}requestedPlayableMs(e,t,i){const s=Array.isArray(e.variant)?e.variant:[e.variant],a=s.find(e=>e.format===t)??s[0];if(!a)return null;if(0===a.assets.length)return null;const d=a.assets.map(e=>e.duration);if(d.some(e=>void 0===e||!Number.isFinite(e)||e<=0))return i;const r=d.reduce((e,t)=>e+(t??0),0);return Math.min(Math.round(1e3*r),i)}updateHeartbeat(){this.guard("setHeartbeatPayload",e=>e.setHeartbeatPayload({custom:{...this.sessionKeys,...this.activeBreakId?{brid:this.activeBreakId}:{},...void 0!==this.activeAdKeys?.adid?{adid:this.activeAdKeys.adid}:{}}}))}resetBreakState(){this.emitPendingAdStart(null),this.activeBreakId=null,this.breakBeginTimestamp=null,this.breakAvailableMs=null,this.breakRequestedMs=null,this.firstAdReported=!1,this.breakFilledMs=0,this.breakWatchedMs=0,this.activeAdKeys=null,this.activeAdCompanion=null,this.activeAdAssetId=null,this.activeAdIsVendor=!1,this.activeAdBaseSec=0,this.breakLastTimeSec=0,this.activeAdWatchedSec=0,this.activeAdDeclaredSec=null,this.activeAdIsVast=!1,this.activeAdResolvedSec=null,this.skipRequestedBreakId=null,this.abortedBreakId=null,this.cutBreakId=null,this.erroredAssetId=null}guard(e,t){const i=this.getHandle();if(i)try{t(i)}catch(t){this.log(`Lens CMCD ${e} failed:`,t)}}}
|
|
@@ -5,7 +5,8 @@ import { Asset } from '../types/BreakManifest';
|
|
|
5
5
|
* reports the real composition per ad at runtime via `StreamEvent.getAd().getAdPodInfo()`.
|
|
6
6
|
* Contract: every `adbegin` gets exactly one `adend`; a new ad closes the previous one even if
|
|
7
7
|
* IMA never reported completion; {@link finish} closes whatever is open; re-reporting the open
|
|
8
|
-
* ad is idempotent (IMA re-fires `STARTED` when a viewer seeks back into an ad).
|
|
8
|
+
* ad is idempotent (IMA re-fires `STARTED` when a viewer seeks back into an ad). IMA can split
|
|
9
|
+
* one pod into several ad breaks, so {@link onAdBreakEnded} only finishes once the last ad was seen.
|
|
9
10
|
*/
|
|
10
11
|
/** One IMA pod-ad report, normalized by the render layer so this module never sees an IMA object. */
|
|
11
12
|
export interface GamPodAdInfo {
|
|
@@ -17,6 +18,8 @@ export interface GamPodAdInfo {
|
|
|
17
18
|
adId?: string | undefined;
|
|
18
19
|
/** IMA's creative id, when available (`getCreativeId()`). */
|
|
19
20
|
creativeId?: string | undefined;
|
|
21
|
+
/** Ad duration in seconds (`getDuration()`); absent or non-positive when IMA reports none. */
|
|
22
|
+
duration?: number | undefined;
|
|
20
23
|
}
|
|
21
24
|
/** One per-ad event for the driver to emit, in order. */
|
|
22
25
|
export interface GamPodAdStep {
|
|
@@ -42,22 +45,32 @@ export interface GamPodCurrentAd {
|
|
|
42
45
|
creativeId?: string | undefined;
|
|
43
46
|
}
|
|
44
47
|
/** Per-ad asset for `adPosition` of `podAsset`: id `<podAssetId>-ad-<position>`, other fields carried over unchanged. */
|
|
45
|
-
export declare function derivePodAdAsset(podAsset: Asset, adPosition: number): Asset;
|
|
48
|
+
export declare function derivePodAdAsset(podAsset: Asset, adPosition: number, durationSec?: number): Asset;
|
|
46
49
|
export declare class GamPodAdTracker {
|
|
47
50
|
private readonly podAsset;
|
|
48
51
|
private open;
|
|
49
52
|
private openPosition;
|
|
50
53
|
private reportedAnyAd;
|
|
51
54
|
private finished;
|
|
55
|
+
private lastPosition;
|
|
56
|
+
private lastTotal;
|
|
52
57
|
constructor(podAsset: Asset);
|
|
53
58
|
/** The ad currently open, or null. Drives quartile attribution. */
|
|
54
59
|
get currentAd(): GamPodCurrentAd | null;
|
|
55
60
|
/** True once IMA reported at least one ad; while false the pod is still reported the legacy way. */
|
|
56
61
|
get sawAnyAd(): boolean;
|
|
62
|
+
/** 1-based position of the last ad IMA reported; 0 before any. */
|
|
63
|
+
get lastAdPosition(): number;
|
|
64
|
+
/** Ads in the pod per the last IMA report; 0 when IMA did not say. */
|
|
65
|
+
get lastTotalAds(): number;
|
|
66
|
+
/** True once IMA reported the pod's last ad, so anything after it is slate. */
|
|
67
|
+
get reportedLastAd(): boolean;
|
|
57
68
|
/** Closes the previous ad if it never completed, then opens the reported one. Idempotent for the open ad. */
|
|
58
69
|
onAdStarted(info: GamPodAdInfo): GamPodAdStep[];
|
|
59
70
|
/** IMA reported the open ad completing. No-op when nothing is open. */
|
|
60
71
|
onAdComplete(): GamPodAdStep[];
|
|
72
|
+
/** IMA ended an ad break while pod stream remains: close the open ad, and finish only after the last ad. */
|
|
73
|
+
onAdBreakEnded(): GamPodAdStep[];
|
|
61
74
|
/** Close whatever is open and refuse further reports, so a late IMA event cannot reopen a finished pod. */
|
|
62
75
|
finish(): GamPodAdStep[];
|
|
63
76
|
/** Emit the `adend` for the open ad, if any, and clear it. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function derivePodAdAsset(t,
|
|
1
|
+
export function derivePodAdAsset(t,i,s){return{...t,id:`${t.id}-ad-${i}`,..."number"==typeof s&&Number.isFinite(s)&&s>0?{duration:s}:{}}}function t(t,i){return"number"==typeof t&&Number.isFinite(t)?Math.max(i,Math.floor(t)):i}export class GamPodAdTracker{constructor(t){this.podAsset=t,this.open=null,this.openPosition=0,this.reportedAnyAd=!1,this.finished=!1,this.lastPosition=0,this.lastTotal=0}get currentAd(){return this.open}get sawAnyAd(){return this.reportedAnyAd}get lastAdPosition(){return this.lastPosition}get lastTotalAds(){return this.lastTotal}get reportedLastAd(){return this.lastTotal>0&&this.lastPosition>=this.lastTotal}onAdStarted(i){if(this.finished)return[];const s=function(t){if("number"!=typeof t||!Number.isFinite(t))return;const i=Math.floor(t);return i>=1?i:void 0}(i.adPosition),e=s??1;if(this.open&&this.openPosition===e)return[];const n=this.closeOpen(),o=e-1;return this.open={asset:derivePodAdAsset(this.podAsset,e,i.duration),adIndex:o,totalAds:t(i.totalAds,e),adPosition:s,adId:i.adId,creativeId:i.creativeId},this.openPosition=e,this.lastPosition=e,this.lastTotal=t(i.totalAds,0),this.reportedAnyAd=!0,n.push({type:"adbegin",...this.open}),n}onAdComplete(){return this.finished?[]:this.closeOpen()}onAdBreakEnded(){return this.finished?[]:this.reportedLastAd?this.finish():this.closeOpen()}finish(){if(this.finished)return[];const t=this.closeOpen();return this.finished=!0,t}closeOpen(){if(!this.open)return[];const t=[{type:"adend",...this.open}];return this.open=null,this.openPosition=0,t}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{buildGamPodUrl as t}from"./GamPodUrlBuilder";import{debugLog as e}from"../diagnostics/debugLog";export class GamStreamManager{constructor(t,e,a=!1){this.videoElement=t,this.adUiContainer=e,this.streamManager=null,this.streamId=null,this.config=null,this.initPromise=null,this.callbacks={},this.debug=a}setCallbacks(t){this.callbacks=t}isImaSdkAvailable(){return"undefined"!=typeof google&&void 0!==google.ima&&void 0!==google.ima.dai&&void 0!==google.ima.dai.api}async initialize(t){return this.streamManager&&this.reset(),this.config=t,this.initPromise=this.doInitialize(),this.initPromise}async initializeLiveStream(t){if(this.streamManager&&this.reset(),!this.isImaSdkAvailable())throw new Error('Google IMA DAI SDK not found. Include <script src="https://imasdk.googleapis.com/js/sdkloader/ima3_dai.js"><\/script> in your page.');const e=this.adUiContainer||this.videoElement.parentElement||document.body;this.streamManager=new google.ima.dai.api.StreamManager(this.videoElement,e);const a=new google.ima.dai.api.LiveStreamRequest;return a.assetKey=t.assetKey,a.format="hls",t.networkCode&&(a.networkCode=t.networkCode),t.adTagParameters&&(a.adTagParameters=t.adTagParameters),t.streamActivityMonitorId&&(a.streamActivityMonitorId=t.streamActivityMonitorId),new Promise((e,i)=>{this.setupEventListeners(void 0,i,t=>e(t)),this.log(`Requesting live stream for asset: ${t.assetKey}`),this.streamManager.requestStream(a)})}async doInitialize(){if(!this.isImaSdkAvailable())throw new Error('Google IMA DAI SDK not found. Include <script src="https://imasdk.googleapis.com/js/sdkloader/ima3_dai.js"><\/script> in your page.');if(!this.config)throw new Error("GamStreamManager config not set");this.log("Initializing IMA StreamManager...");const t=this.adUiContainer||this.videoElement.parentElement||document.body;this.streamManager=new google.ima.dai.api.StreamManager(this.videoElement,t);const e=new google.ima.dai.api.PodStreamRequest;return e.networkCode=this.config.networkCode,e.customAssetKey=this.config.customAssetKey,e.format="hls",this.config.adTagParameters&&(e.adTagParameters=this.config.adTagParameters),this.config.streamActivityMonitorId&&(e.streamActivityMonitorId=this.config.streamActivityMonitorId),new Promise((t,a)=>{this.setupEventListeners(t,a),this.log(`Requesting stream for network: ${this.config.networkCode}, asset: ${this.config.customAssetKey}`),this.streamManager.requestStream(e)})}setupEventListeners(t,e,a){if(!this.streamManager)return;const i=google.ima.dai.api.StreamEvent.Type;this.streamManager.addEventListener(i.STREAM_INITIALIZED,e=>{const a=e.getStreamData();this.streamId=a.streamId,this.log(`Stream initialized, streamId: ${this.streamId}`),t?.()}),this.streamManager.addEventListener(i.LOADED,t=>{const e=t.getStreamData();this.streamId=e.streamId,e.url&&(this.log(`Stream loaded, url: ${e.url}`),a?.(e.url))}),this.streamManager.addEventListener(i.AD_BREAK_STARTED,()=>{this.log("Ad break started"),this.callbacks.onAdBreakStarted?.()}),this.streamManager.addEventListener(i.AD_BREAK_ENDED,()=>{this.log("Ad break ended"),this.callbacks.onAdBreakEnded?.()}),this.streamManager.addEventListener(i.STARTED,t=>{const e=function(t){const e=t.getAd?.();if(!e)return;const a=e.getAdPodInfo?.();return{adPosition:a?.getAdPosition(),totalAds:a?.getTotalAds(),adId:e.getAdId?.(),creativeId:e.getCreativeId?.()}}(t);this.log(`Ad started (ad ${e?.adPosition??"?"} of ${e?.totalAds??"?"})`),this.callbacks.onAdStarted?.(e)}),this.streamManager.addEventListener(i.COMPLETE,()=>{this.log("Ad complete"),this.callbacks.onAdComplete?.()}),this.streamManager.addEventListener(i.FIRST_QUARTILE,()=>{this.log("Ad first quartile"),this.callbacks.onAdFirstQuartile?.()}),this.streamManager.addEventListener(i.MIDPOINT,()=>{this.log("Ad midpoint"),this.callbacks.onAdMidpoint?.()}),this.streamManager.addEventListener(i.THIRD_QUARTILE,()=>{this.log("Ad third quartile"),this.callbacks.onAdThirdQuartile?.()}),this.streamManager.addEventListener(i.ERROR,t=>{const a=t.getStreamData().errorMessage||"Unknown IMA error";this.log(`IMA error: ${a}`),e?.(new Error(`IMA stream initialization failed: ${a}`)),this.callbacks.onError?.(a)})}getStreamId(){return this.streamId}isInitialized(){return null!==this.streamId}replaceAdTagParameters(t){this.streamManager&&this.streamId?(this.streamManager.replaceAdTagParameters(t),this.log("Ad tag parameters replaced")):this.log("replaceAdTagParameters called but stream not initialized — ignoring")}processTimedMetadata(t){if(this.streamManager)if(t.raw&&t.raw.length>0){if("presented"===t.phase)return;this.streamManager.processMetadata("ID3",t.raw,t.startTime)}else"parsed"!==t.phase&&(t.frames&&Object.keys(t.frames).length>0?this.streamManager.onTimedMetadata(t.frames):t.messageData&&this.streamManager.onTimedMetadata({TXXX:t.messageData}))}buildPodUrl(e,a,i){if(!this.streamId)throw new Error("GamStreamManager not initialized. Call initialize() first.");const s=t(e,i,this.streamId,a);return this.log(`Built pod URL: ${s}`),s}reset(){this.streamManager&&this.streamManager.reset(),this.streamId=null,this.initPromise=null,this.streamManager=null,this.log("Stream manager reset")}destroy(){this.reset(),this.config=null,this.callbacks={}}log(t){this.debug&&e(`[GamStreamManager] ${t}`)}}
|
|
1
|
+
import{buildGamPodUrl as t}from"./GamPodUrlBuilder";import{debugLog as e}from"../diagnostics/debugLog";export class GamStreamManager{constructor(t,e,a=!1){this.videoElement=t,this.adUiContainer=e,this.streamManager=null,this.streamId=null,this.config=null,this.initPromise=null,this.callbacks={},this.debug=a}setCallbacks(t){this.callbacks=t}isImaSdkAvailable(){return"undefined"!=typeof google&&void 0!==google.ima&&void 0!==google.ima.dai&&void 0!==google.ima.dai.api}async initialize(t){return this.streamManager&&this.reset(),this.config=t,this.initPromise=this.doInitialize(),this.initPromise}async initializeLiveStream(t){if(this.streamManager&&this.reset(),!this.isImaSdkAvailable())throw new Error('Google IMA DAI SDK not found. Include <script src="https://imasdk.googleapis.com/js/sdkloader/ima3_dai.js"><\/script> in your page.');const e=this.adUiContainer||this.videoElement.parentElement||document.body;this.streamManager=new google.ima.dai.api.StreamManager(this.videoElement,e);const a=new google.ima.dai.api.LiveStreamRequest;return a.assetKey=t.assetKey,a.format="hls",t.networkCode&&(a.networkCode=t.networkCode),t.adTagParameters&&(a.adTagParameters=t.adTagParameters),t.streamActivityMonitorId&&(a.streamActivityMonitorId=t.streamActivityMonitorId),new Promise((e,i)=>{this.setupEventListeners(void 0,i,t=>e(t)),this.log(`Requesting live stream for asset: ${t.assetKey}`),this.streamManager.requestStream(a)})}async doInitialize(){if(!this.isImaSdkAvailable())throw new Error('Google IMA DAI SDK not found. Include <script src="https://imasdk.googleapis.com/js/sdkloader/ima3_dai.js"><\/script> in your page.');if(!this.config)throw new Error("GamStreamManager config not set");this.log("Initializing IMA StreamManager...");const t=this.adUiContainer||this.videoElement.parentElement||document.body;this.streamManager=new google.ima.dai.api.StreamManager(this.videoElement,t);const e=new google.ima.dai.api.PodStreamRequest;return e.networkCode=this.config.networkCode,e.customAssetKey=this.config.customAssetKey,e.format="hls",this.config.adTagParameters&&(e.adTagParameters=this.config.adTagParameters),this.config.streamActivityMonitorId&&(e.streamActivityMonitorId=this.config.streamActivityMonitorId),new Promise((t,a)=>{this.setupEventListeners(t,a),this.log(`Requesting stream for network: ${this.config.networkCode}, asset: ${this.config.customAssetKey}`),this.streamManager.requestStream(e)})}setupEventListeners(t,e,a){if(!this.streamManager)return;const i=google.ima.dai.api.StreamEvent.Type;this.streamManager.addEventListener(i.STREAM_INITIALIZED,e=>{const a=e.getStreamData();this.streamId=a.streamId,this.log(`Stream initialized, streamId: ${this.streamId}`),t?.()}),this.streamManager.addEventListener(i.LOADED,t=>{const e=t.getStreamData();this.streamId=e.streamId,e.url&&(this.log(`Stream loaded, url: ${e.url}`),a?.(e.url))}),this.streamManager.addEventListener(i.AD_BREAK_STARTED,()=>{this.log("Ad break started"),this.callbacks.onAdBreakStarted?.()}),this.streamManager.addEventListener(i.AD_BREAK_ENDED,()=>{this.log("Ad break ended"),this.callbacks.onAdBreakEnded?.()}),this.streamManager.addEventListener(i.STARTED,t=>{const e=function(t){const e=t.getAd?.();if(!e)return;const a=e.getAdPodInfo?.();return{adPosition:a?.getAdPosition(),totalAds:a?.getTotalAds(),adId:e.getAdId?.(),creativeId:e.getCreativeId?.(),duration:e.getDuration?.()}}(t);this.log(`Ad started (ad ${e?.adPosition??"?"} of ${e?.totalAds??"?"})`),this.callbacks.onAdStarted?.(e)}),this.streamManager.addEventListener(i.COMPLETE,()=>{this.log("Ad complete"),this.callbacks.onAdComplete?.()}),this.streamManager.addEventListener(i.FIRST_QUARTILE,()=>{this.log("Ad first quartile"),this.callbacks.onAdFirstQuartile?.()}),this.streamManager.addEventListener(i.MIDPOINT,()=>{this.log("Ad midpoint"),this.callbacks.onAdMidpoint?.()}),this.streamManager.addEventListener(i.THIRD_QUARTILE,()=>{this.log("Ad third quartile"),this.callbacks.onAdThirdQuartile?.()}),this.streamManager.addEventListener(i.ERROR,t=>{const a=t.getStreamData().errorMessage||"Unknown IMA error";this.log(`IMA error: ${a}`),e?.(new Error(`IMA stream initialization failed: ${a}`)),this.callbacks.onError?.(a)})}getStreamId(){return this.streamId}isInitialized(){return null!==this.streamId}replaceAdTagParameters(t){this.streamManager&&this.streamId?(this.streamManager.replaceAdTagParameters(t),this.log("Ad tag parameters replaced")):this.log("replaceAdTagParameters called but stream not initialized — ignoring")}processTimedMetadata(t){if(this.streamManager)if(t.raw&&t.raw.length>0){if("presented"===t.phase)return;this.streamManager.processMetadata("ID3",t.raw,t.startTime)}else"parsed"!==t.phase&&(t.frames&&Object.keys(t.frames).length>0?this.streamManager.onTimedMetadata(t.frames):t.messageData&&this.streamManager.onTimedMetadata({TXXX:t.messageData}))}buildPodUrl(e,a,i){if(!this.streamId)throw new Error("GamStreamManager not initialized. Call initialize() first.");const s=t(e,i,this.streamId,a);return this.log(`Built pod URL: ${s}`),s}reset(){this.streamManager&&this.streamManager.reset(),this.streamId=null,this.initPromise=null,this.streamManager=null,this.log("Stream manager reset")}destroy(){this.reset(),this.config=null,this.callbacks={}}log(t){this.debug&&e(`[GamStreamManager] ${t}`)}}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import type { LensHandle } from '../vendor/lens-sdk/index.js';
|
|
1
|
+
import type { LensBatch, LensHandle } from '../vendor/lens-sdk/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* The Ads SDK's product identity in Lens: bound at join, spanning every session
|
|
4
4
|
* of this SDK instance. Lens destination filters key on it.
|
|
5
5
|
*/
|
|
6
6
|
export declare const LENS_NAMESPACE = "ads";
|
|
7
|
+
/** Batch built-in ingest reports without changing Lens's default heartbeat cadence. */
|
|
8
|
+
export declare const LENS_BATCH: LensBatch;
|
|
7
9
|
/**
|
|
8
10
|
* Ties Lens observability to the Ads SDK session lifecycle. Always on and not
|
|
9
11
|
* integrator-configurable — no public config option reaches this class.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Lens as s}from"../vendor/lens-sdk/index.js";import{configureLensBackend as e}from"./lensBackend";export const LENS_NAMESPACE="ads";export class LensReporter{constructor(s=()=>{}){this.log=s,this.lensHandle=null,this.joinFailed=!1,this.destroyed=!1}get handle(){return this.lensHandle}startSession(){const s=this.join();if(s)try{s.startSession()}catch(s){this.log("Lens session start failed:",s)}}endSession(){if(this.lensHandle)try{this.lensHandle.endSession()}catch(s){this.log("Lens session end failed:",s)}}destroy(){this.destroyed=!0;const s=this.lensHandle;if(this.lensHandle=null,s)try{s.dispose()}catch(s){this.log("Lens dispose failed:",s)}}join(){if(this.lensHandle)return this.lensHandle;if(this.destroyed||this.joinFailed)return null;try{e()}catch(s){this.log("Lens backend selection failed:",s)}try{this.lensHandle=s.join({namespace:"ads"})}catch(s){this.joinFailed=!0,this.log("Lens join failed:",s)}return this.lensHandle}}
|
|
1
|
+
import{Lens as s}from"../vendor/lens-sdk/index.js";import{configureLensBackend as e}from"./lensBackend";export const LENS_NAMESPACE="ads";export const LENS_BATCH={maxEvents:10,maxDelayMs:6e4};export class LensReporter{constructor(s=()=>{}){this.log=s,this.lensHandle=null,this.joinFailed=!1,this.destroyed=!1}get handle(){return this.lensHandle}startSession(){const s=this.join();if(s)try{s.startSession()}catch(s){this.log("Lens session start failed:",s)}}endSession(){if(this.lensHandle)try{this.lensHandle.endSession()}catch(s){this.log("Lens session end failed:",s)}}destroy(){this.destroyed=!0;const s=this.lensHandle;if(this.lensHandle=null,s)try{s.dispose()}catch(s){this.log("Lens dispose failed:",s)}}join(){if(this.lensHandle)return this.lensHandle;if(this.destroyed||this.joinFailed)return null;try{e()}catch(s){this.log("Lens backend selection failed:",s)}try{this.lensHandle=s.join({namespace:"ads",batch:LENS_BATCH})}catch(s){this.joinFailed=!0,this.log("Lens join failed:",s)}return this.lensHandle}}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { PlayerAdapter } from '../interfaces/PlayerAdapter';
|
|
2
|
+
import type { LiveStartPushbackConfig, PtsSource } from '../types/OptiViewAdsConfig';
|
|
3
|
+
/** Whether the startup adjustment applies, and which setting decided it. */
|
|
4
|
+
export interface LiveStartEnablement {
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
enabledBy: 'config' | 'ptsSource';
|
|
7
|
+
}
|
|
8
|
+
/** An explicit `enabled` wins; otherwise the adjustment follows Anvato cue signaling. */
|
|
9
|
+
export declare function resolveLiveStartEnablement(config: LiveStartPushbackConfig | undefined, ptsSource: PtsSource | undefined): LiveStartEnablement;
|
|
10
|
+
interface LiveStartPushbackDeps {
|
|
11
|
+
blocked: () => boolean;
|
|
12
|
+
setSeeking: (active: boolean) => void;
|
|
13
|
+
diagnose: (code: string, message: string, context: Record<string, unknown>) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare class LiveStartPushbackController {
|
|
16
|
+
private readonly player;
|
|
17
|
+
private readonly config;
|
|
18
|
+
private readonly deps;
|
|
19
|
+
private armed;
|
|
20
|
+
private playbackSeen;
|
|
21
|
+
private startOffsetRequested;
|
|
22
|
+
private generation;
|
|
23
|
+
private cleanupLanding;
|
|
24
|
+
private readonly enablement;
|
|
25
|
+
constructor(player: PlayerAdapter, config: LiveStartPushbackConfig | undefined, deps: LiveStartPushbackDeps, ptsSource?: PtsSource);
|
|
26
|
+
start(): void;
|
|
27
|
+
stop(): void;
|
|
28
|
+
private disarm;
|
|
29
|
+
private readonly onPlaying;
|
|
30
|
+
private readonly attempt;
|
|
31
|
+
/** The engine already began at the requested distance: report it measured, with no seek. */
|
|
32
|
+
private reportStartOffset;
|
|
33
|
+
private publishedEdge;
|
|
34
|
+
private skip;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{contentSeekableEnd as e}from"./adPlayer/liveEdge";import{resolveLiveStartPushback as t}from"./resolveLiveStartPushback";export function resolveLiveStartEnablement(e,t){return"boolean"==typeof e?.enabled?{enabled:e.enabled,enabledBy:"config"}:{enabled:"anvatoCue"===t,enabledBy:"ptsSource"}}const i=e=>"number"==typeof e&&Number.isFinite(e)&&e>0,s=e=>Math.round(1e3*e)/1e3;export class LiveStartPushbackController{constructor(a,n,r,l){this.player=a,this.config=n,this.deps=r,this.armed=!1,this.playbackSeen=!1,this.startOffsetRequested=!1,this.generation=0,this.cleanupLanding=null,this.onPlaying=()=>{this.playbackSeen=!0,this.attempt()},this.attempt=()=>{if(!this.playbackSeen)return;if(!this.armed||this.deps.blocked()||this.player.paused||!1===this.player.playbackReady)return;const a=this.player.isLive??(this.player.duration===1/0||!Number.isFinite(this.player.duration)&&null);if(null===a)return;const n=this.startOffsetRequested;if(this.disarm(),this.startOffsetRequested=!1,!a)return;const r=this.player.targetDuration,l=i(r)?r:this.config?.targetDurationSeconds,o=this.config?.minimumDistanceTargetDurations??5,d=this.player.currentTime,u=e(this.player),h=this.publishedEdge(u),f=this.player.videoElement?.seekable,g=this.player.seekableStart??(f?.length?f.start(f.length-1):null),p={enabledBy:this.enablement.enabledBy,position:d,seekableStart:g,seekableEnd:u,liveEdge:h,liveEdgeSource:i(this.player.liveEdge)?"adapter":"seekable",targetDurationSec:i(l)?l:null,targetDurationSource:i(r)?"adapter":i(l)?"config":"unavailable",requestedOffsetTargetDurations:o,startOffsetRequested:n};let c=null;if(i(l)?i(o)&&Number.isFinite(l*o)?(null===h||null===g||!Number.isFinite(g)||h<=g||!Number.isFinite(d))&&(c="no-range"):c="invalid-config":c="no-target-duration",!c&&i(l)&&null!==h&&Object.assign(p,{initialOffsetSec:s(h-d),initialOffsetTargetDurations:s((h-d)/l),requestedOffsetSec:s(o*l)}),!this.enablement.enabled)return void this.skip("disabled",p);if(c||!i(l)||null===h||null===g)return void this.skip(c??"no-range",p);if(n&&h-d>=o*l-.25)return void this.reportStartOffset(d,h,l,o,p);const y=t(d,g,h,l,o);if(null===y)return void this.skip(h-d>=o*l?"already-behind":"no-backward-target",p);Object.assign(p,{target:y,rewindSec:s(d-y),rewindTargetDurations:s((d-y)/l),targetOffsetSec:s(h-y),targetOffsetTargetDurations:s((h-y)/l),windowClamped:y>h-o*l,method:"seek"});const b=this.generation;this.deps.setSeeking(!0);const m=t=>{if(b!==this.generation||!this.cleanupLanding)return;this.cleanupLanding();const i="seeked"===t?this.player.currentTime:null,a=this.publishedEdge(e(this.player)),n=null!==i&&Number.isFinite(i)&&null!==a?a-i:null;this.deps.diagnose("DA-LIVE-START-PUSHBACK-LANDED",`Live start landing: TD=${l}s, offset=${null===n?"unknown":`${s(n)}s (${s(n/l)}xTD)`}, ${t}`,{...p,reason:t,landed:i,liveEdgeAtLanding:a,landedOffsetSec:null===n?null:s(n),landedOffsetTargetDurations:null===n?null:s(n/l),errorSec:null===i?null:s(i-y)})},S=()=>m("seeked"),D=setTimeout(()=>m("timeout"),1e4);if(this.cleanupLanding=()=>{this.cleanupLanding=null,clearTimeout(D),this.player.off("seeked",S),this.deps.setSeeking(!1)},this.player.on("seeked",S),this.deps.diagnose("DA-LIVE-START-PUSHBACK",`Live start: TD=${l}s, offset=${p.initialOffsetSec}s (${p.initialOffsetTargetDurations}xTD), requested=${o*l}s (${o}xTD), rewind=${p.rewindSec}s (${p.rewindTargetDurations}xTD), target=${y}s`,p),b===this.generation)try{this.player.seek(y)}catch{m("seek-failed")}},this.enablement=resolveLiveStartEnablement(n,l)}start(){this.stop(),this.armed=!0,this.playbackSeen=!this.player.paused&&!1!==this.player.playbackReady;const e=this.config?.minimumDistanceTargetDurations??5,t=i(this.player.targetDuration)?this.player.targetDuration:i(this.config?.targetDurationSeconds)?this.config.targetDurationSeconds:null;this.startOffsetRequested=this.enablement.enabled&&i(e)&&!0===this.player.requestLiveStartOffset?.(e,t),this.player.on("playing",this.onPlaying),this.player.on("timeupdate",this.attempt),this.attempt()}stop(){this.generation++,this.disarm(),this.cleanupLanding?.()}disarm(){this.armed=!1,this.player.off("playing",this.onPlaying),this.player.off("timeupdate",this.attempt),this.startOffsetRequested&&this.player.requestLiveStartOffset?.(null,null)}reportStartOffset(e,t,i,a,n){const r=t-a*i,l=t-e,o={...n,target:s(r),rewindSec:0,rewindTargetDurations:0,targetOffsetSec:s(a*i),targetOffsetTargetDurations:s(a),windowClamped:!1,method:"start-offset"};this.deps.diagnose("DA-LIVE-START-PUSHBACK",`Live start: TD=${i}s, began ${s(l)}s (${s(l/i)}xTD) behind live via the engine start offset, requested=${s(a*i)}s (${a}xTD), no seek`,o),this.deps.diagnose("DA-LIVE-START-PUSHBACK-LANDED",`Live start landing: TD=${i}s, offset=${s(l)}s (${s(l/i)}xTD), start-offset`,{...o,reason:"start-offset",landed:e,liveEdgeAtLanding:t,landedOffsetSec:s(l),landedOffsetTargetDurations:s(l/i),errorSec:s(e-r)})}publishedEdge(e){const t=this.player.liveEdge;return!i(t)||t-this.player.currentTime>=86400?e:null===e?t:Math.max(t,e)}skip(e,t){this.deps.diagnose("DA-LIVE-START-PUSHBACK-SKIPPED",`Live start unchanged: ${e}, TD=${t.targetDurationSec??"unknown"}s, offset=${t.initialOffsetSec??"unknown"}s (${t.initialOffsetTargetDurations??"unknown"}xTD)`,{...t,reason:e})}}
|
|
@@ -23,15 +23,30 @@ export declare function anvatoPayloadFromCue(cue: TimedMetadataCue): string | nu
|
|
|
23
23
|
* split on `&`, then on the FIRST `=`, `+` as space, percent-decode, raw text on failure, first duplicate wins.
|
|
24
24
|
*/
|
|
25
25
|
export declare function parseAnvatoPayload(payload: string): Record<string, string>;
|
|
26
|
+
/** How far before its `startTime` a `ptsOffset`-placed cue may land (frame rounding between the two clocks). */
|
|
27
|
+
export declare const PTS_OFFSET_MIN_LEAD_SECONDS = 0.1;
|
|
28
|
+
/** How far after its `startTime` (the carrying segment's start) a `ptsOffset`-placed cue may land. */
|
|
29
|
+
export declare const PTS_OFFSET_MAX_LAG_SECONDS = 15;
|
|
30
|
+
/** Structured-diagnostic sink for the tracker. Optional; absent means silent. */
|
|
31
|
+
export type CueTrackerDiagnose = (code: 'DA-ANVATO-CUE-SEGMENT-ANCHORED' | 'DA-ANVATO-CUE-OFFSET-REJECTED', message: string, context: Record<string, unknown>) => void;
|
|
26
32
|
/**
|
|
27
33
|
* Maps a break's manifest `pts` to the media time its Anvato cue was observed at. With
|
|
28
34
|
* `ptsSource: 'anvatoCue'` a PTS break is only schedulable once its cue was seen. Portable brain logic.
|
|
35
|
+
*
|
|
36
|
+
* A cue's `startTime` is only the cue's own PTS for ID3. A DASH emsg v0 with a zero delta reports
|
|
37
|
+
* the start of its carrying segment, so the adapter supplies `ptsOffset` and the cue is placed at
|
|
38
|
+
* `pts + ptsOffset`, provided that lands inside the carrying segment's plausible window.
|
|
29
39
|
*/
|
|
30
40
|
export declare class MetadataCueTracker {
|
|
41
|
+
private readonly diagnose?;
|
|
31
42
|
/** Observed cue `pts` parameter (seconds) → cue media time (seconds). */
|
|
32
43
|
private mediaTimeByPts;
|
|
44
|
+
private segmentAnchoredDiagnosed;
|
|
45
|
+
private offsetRejectedPts;
|
|
46
|
+
constructor(diagnose?: CueTrackerDiagnose | undefined);
|
|
33
47
|
/** Ignores non-Anvato cues, non-`type=cue` payloads, and non-finite `pts`. True when a cue was recorded or refreshed. */
|
|
34
48
|
handleCue(cue: TimedMetadataCue): boolean;
|
|
49
|
+
private resolveMediaTime;
|
|
35
50
|
/**
|
|
36
51
|
* Media time of the cue matching `pts` within {@link PTS_MATCH_TOLERANCE_SECONDS}, or null.
|
|
37
52
|
* Closest wins; ties resolve to the lower cue PTS so the result is observation-order independent.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{decodeUtf8 as e,parseId3GeobFrames as t}from"../id3/parseId3Geob";export const ANVATO_ID3_DESCRIPTION="Anvatos";export const ANVATO_ID3_MIME_TYPE="application/json";export const ANVATO_EMSG_SCHEME_ID_URI="urn:anvato:es1:052016";export const ID3_IN_EMSG_SCHEME_ID_URIS=["https://aomedia.org/emsg/ID3","https://developer.apple.com/streaming/emsg-id3"];export function isId3InEmsgScheme(e){return void 0!==e&&ID3_IN_EMSG_SCHEME_ID_URIS.includes(e)}export const PTS_MATCH_TOLERANCE_SECONDS=.005;export function isAnvatoCue(e){return"id3"===e.type?"Anvatos"===e.description&&(void 0===e.mimeType||"application/json"===e.mimeType):"emsg"===e.type&&"urn:anvato:es1:052016"===e.schemeIdUri}export function anvatoPayloadFromCue(
|
|
1
|
+
import{decodeUtf8 as e,parseId3GeobFrames as t}from"../id3/parseId3Geob";export const ANVATO_ID3_DESCRIPTION="Anvatos";export const ANVATO_ID3_MIME_TYPE="application/json";export const ANVATO_EMSG_SCHEME_ID_URI="urn:anvato:es1:052016";export const ID3_IN_EMSG_SCHEME_ID_URIS=["https://aomedia.org/emsg/ID3","https://developer.apple.com/streaming/emsg-id3"];export function isId3InEmsgScheme(e){return void 0!==e&&ID3_IN_EMSG_SCHEME_ID_URIS.includes(e)}export const PTS_MATCH_TOLERANCE_SECONDS=.005;export function isAnvatoCue(e){return"id3"===e.type?"Anvatos"===e.description&&(void 0===e.mimeType||"application/json"===e.mimeType):"emsg"===e.type&&"urn:anvato:es1:052016"===e.schemeIdUri}export function anvatoPayloadFromCue(s){if(isAnvatoCue(s))return s.messageData??null;if("emsg"===s.type&&isId3InEmsgScheme(s.schemeIdUri)&&s.raw)for(const i of t(s.raw))if("Anvatos"===i.description&&"application/json"===i.mimeType)return e(i.data);return null}export function parseAnvatoPayload(e){const t={};for(const i of e.split("&")){if(""===i)continue;const e=i.indexOf("="),n=-1===e?i:i.slice(0,e),o=-1===e?"":i.slice(e+1),r=s(n);r in t||(t[r]=s(o))}return t}function s(e){const t=e.replace(/\+/g," ");try{return decodeURIComponent(t)}catch{return t}}export const PTS_OFFSET_MIN_LEAD_SECONDS=.1;export const PTS_OFFSET_MAX_LAG_SECONDS=15;export class MetadataCueTracker{constructor(e){this.diagnose=e,this.mediaTimeByPts=new Map,this.segmentAnchoredDiagnosed=!1,this.offsetRejectedPts=new Set}handleCue(e){if(!Number.isFinite(e.startTime))return!1;const t=anvatoPayloadFromCue(e);if(!t)return!1;const s=parseAnvatoPayload(t);if("cue"!==s.type)return!1;const i=Number(s.pts);return!!Number.isFinite(i)&&(this.mediaTimeByPts.set(i,this.resolveMediaTime(e,i)),!0)}resolveMediaTime(e,t){const s=e.ptsOffset;if("number"!=typeof s||!Number.isFinite(s))return"urn:anvato:es1:052016"!==e.schemeIdUri||this.segmentAnchoredDiagnosed||(this.segmentAnchoredDiagnosed=!0,this.diagnose?.("DA-ANVATO-CUE-SEGMENT-ANCHORED",`Anvato emsg cue pts=${t} has no ptsOffset; scheduling it at its segment start ${e.startTime}s, which can be up to one segment early.`,{pts:t,mediaTime:e.startTime})),e.startTime;const i=t=>t>=e.startTime-.1&&t<=e.startTime+15,n=t+s;if(i(n))return n;const o=t/1e3+s;return i(o)?o:(this.offsetRejectedPts.has(t)||(this.offsetRejectedPts.add(t),this.diagnose?.("DA-ANVATO-CUE-OFFSET-REJECTED",`Anvato cue pts=${t} maps to ${n}s with ptsOffset ${s}, outside its segment window from ${e.startTime}s; using the segment start.`,{pts:t,startTime:e.startTime,ptsOffset:s,mappedTime:n})),e.startTime)}mediaTimeForPts(e){let t=null,s=1/0;for(const i of this.mediaTimeByPts.keys()){const n=Math.abs(i-e);n>.005||(n<s||n===s&&i<t)&&(t=i,s=n)}return null===t?null:this.mediaTimeByPts.get(t)}get size(){return this.mediaTimeByPts.size}clear(){this.mediaTimeByPts.clear(),this.segmentAnchoredDiagnosed=!1,this.offsetRejectedPts.clear()}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{applyAssetParameterMacros as
|
|
1
|
+
import{objectEntries as e}from"./runtimeObject";import{applyAssetParameterMacros as t,omitBreakScopedParameters as a}from"./assetParameterMacros";import{buildAssetParameterMacroTable as s}from"./assetParameterMacroTable";import{resolveAssetParameters as r}from"./resolveAssetParameters";import{AssetType as i,MediaType as o,BreakFormat as n}from"../types/BreakManifest";import{GamStreamManager as m}from"./GamStreamManager";import{resolveBreakFormat as d}from"./AdBreakSequencer";import{buildStitcherMasterUrl as h}from"./StitcherUrlBuilder";export class SsaiController{constructor(e,t,a){this.player=e,this.options=t,this.callbacks=a,this.gamStreamManager=null,this.breakCounter=0,this.adIndexInBreak=0,this.currentBreak=null,this.currentAsset=null,this.customerMacros={},this.onTimedMetadata=e=>{if(!e)return;const t=e;this.gamStreamManager?.processTimedMetadata(t)}}async start(e){const t=this.player.videoElement;if(!t)throw new Error("SSAI mode requires a content PlayerAdapter that exposes a videoElement (for IMA DAI).");if(!e.customAssetKey)throw new Error("SSAI mode requires a customAssetKey in startSession().");this.sessionConfigParameters=e.assetParameters,this.updatedParameters=void 0,this.manifestParameters=void 0,this.customerMacros={...e.assetParameterMacros};const a=new m(t,void 0,this.options.debug);a.setCallbacks(this.buildGamCallbacks()),this.gamStreamManager=a,await a.initialize({networkCode:this.options.ssai.networkCode,customAssetKey:e.customAssetKey,adTagParameters:this.resolveAdTagParameters(),streamActivityMonitorId:this.options.gam.streamActivityMonitorId});const s=a.getStreamId();if(!s)throw new Error("SSAI mode: IMA DAI session did not return a stream id.");const r=h({stitcherUrl:e.stitcherUrl,streamId:s,maxBitrate:this.options.maxBitrate});this.callbacks.log("SSAI stitched master URL:",r),this.player.on("timedmetadata",this.onTimedMetadata),await this.player.load(r),this.options.autoplay&&await this.player.play()}async startSteered(e,t,a){const s=this.player.videoElement;if(!s)throw new Error("SSAI mode requires a content PlayerAdapter that exposes a videoElement (for IMA DAI).");this.sessionConfigParameters=t,this.updatedParameters=void 0,this.manifestParameters=e.assetParameters,this.customerMacros={...a};const r=new m(s,void 0,this.options.debug);r.setCallbacks(this.buildGamCallbacks()),this.gamStreamManager=r;const i=await r.initializeLiveStream({assetKey:e.assetKey,networkCode:e.networkCode,adTagParameters:this.resolveAdTagParameters(),streamActivityMonitorId:this.options.gam.streamActivityMonitorId});this.callbacks.log("SSAI full-service DAI stream URL:",i),this.player.on("timedmetadata",this.onTimedMetadata),await this.player.load(i),this.options.autoplay&&await this.player.play()}resolveAdTagParameters(){const e=r(this.sessionConfigParameters,this.updatedParameters,this.manifestParameters,void 0),i=t(a(e),s({customerMacros:this.customerMacros,element:this.player.videoElement??null,breakDurationSec:void 0}),"gam");for(const{key:e,macro:t}of i.unresolved)this.callbacks.diagnose("DA-ASSET-MACRO-UNKNOWN",`Asset parameter '${e}' sent with literal macro '${t}': the macro has no value.`,{key:e,macro:t});for(const{key:e,macro:t,pair:a}of i.omitted)this.callbacks.diagnose("DA-ASSET-PARAMETER-OMITTED",`Asset parameter '${e}' not sent: macro '${t}' is empty.`,{key:e,macro:t,...void 0!==a?{pair:a}:{}});return i.params}updateAssetParameters(e){this.updatedParameters=e,this.gamStreamManager?.replaceAdTagParameters(this.resolveAdTagParameters()??{})}updateAssetParameterMacros(t){const a={...this.customerMacros};for(const[s,r]of e(t))void 0===r?delete a[s]:a[s]=r;this.customerMacros=a,this.callbacks.diagnose("DA-ASSET-PARAMETERS-UPDATED","Asset parameter macros updated.",{source:"macros",keys:Object.keys(t).sort()}),this.gamStreamManager?.replaceAdTagParameters(this.resolveAdTagParameters()??{})}get sessionAssetParameterMacros(){return{...this.customerMacros}}setManifestAssetParameters(e){(function(e,t){e&&0===Object.keys(e).length&&(e=void 0);t&&0===Object.keys(t).length&&(t=void 0);if(e===t)return!0;if(!e||!t)return!1;const a=Object.keys(e);return a.length===Object.keys(t).length&&a.every(a=>e[a]===t[a])})(this.manifestParameters,e)||(this.manifestParameters=e,this.gamStreamManager&&(this.gamStreamManager.replaceAdTagParameters(this.resolveAdTagParameters()??{}),this.callbacks.diagnose("DA-ASSET-PARAMETERS-UPDATED","Manifest asset parameters changed; IMA targeting updated.",{source:"manifest",keys:Object.keys(e??{}).sort()})))}stop(){this.player.off("timedmetadata",this.onTimedMetadata),this.gamStreamManager?.destroy(),this.gamStreamManager=null,this.sessionConfigParameters=void 0,this.updatedParameters=void 0,this.manifestParameters=void 0,this.customerMacros={},this.currentBreak=null,this.currentAsset=null,this.breakCounter=0,this.adIndexInBreak=0}buildGamCallbacks(){return{onAdBreakStarted:()=>{this.breakCounter+=1,this.adIndexInBreak=0,this.currentBreak=this.synthBreak(`ssai-break-${this.breakCounter}`),this.callbacks.emit("adbreakbegin",{type:"adbreakbegin",timestamp:Date.now(),break:this.currentBreak,format:d(this.currentBreak),elapsedSec:0,remainingSec:this.currentBreak.duration})},onAdStarted:e=>{const t=this.ensureBreak(),a=this.adIndexInBreak;this.adIndexInBreak+=1,this.currentAsset=this.synthAsset(`${t.id}-ad-${this.adIndexInBreak}`),this.callbacks.emit("adbegin",{type:"adbegin",timestamp:Date.now(),break:t,format:d(t),asset:this.currentAsset,adIndex:a,totalAds:0,...void 0!==e?.adPosition&&Number.isInteger(e.adPosition)&&e.adPosition>=1?{podPosition:e.adPosition}:{}})},onAdFirstQuartile:()=>this.emitQuartile("adfirstquartile"),onAdMidpoint:()=>this.emitQuartile("admidpoint"),onAdThirdQuartile:()=>this.emitQuartile("adthirdquartile"),onAdComplete:()=>{const e=this.ensureBreak(),t=this.currentAsset??this.synthAsset(`${e.id}-ad`);this.callbacks.emit("adend",{type:"adend",timestamp:Date.now(),break:e,format:d(e),asset:t,adIndex:Math.max(0,this.adIndexInBreak-1),totalAds:0}),this.currentAsset=null},onAdBreakEnded:()=>{const e=this.ensureBreak();this.callbacks.emit("adbreakend",{type:"adbreakend",timestamp:Date.now(),break:e,format:d(e)}),this.currentBreak=null,this.currentAsset=null},onError:e=>{this.callbacks.diagnose("DA-SSAI-IMA-ERROR",e),this.callbacks.emit("aderror",{type:"aderror",timestamp:Date.now(),source:"ad",...this.currentBreak?{break:this.currentBreak,format:d(this.currentBreak)}:{},...this.currentAsset?{asset:this.currentAsset}:{},error:new Error(e)})}}}emitQuartile(e){const t=this.ensureBreak(),a=this.currentAsset??this.synthAsset(`${t.id}-ad`);this.callbacks.emit(e,{type:e,timestamp:Date.now(),break:t,format:d(t),asset:a})}ensureBreak(){return this.currentBreak||(this.breakCounter+=1,this.currentBreak=this.synthBreak(`ssai-break-${this.breakCounter}`)),this.currentBreak}synthBreak(e){return{id:e,start:this.player.currentTime,duration:0,variant:{format:n.SINGLE,assets:[]}}}synthAsset(e){return{id:e,type:i.STATIC,mediaType:o.VIDEO,uri:""}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
import{objectEntries as r}from"./runtimeObject";function t(r){return encodeURIComponent(r).replace(/[!'()*]/g,r=>"%"+r.charCodeAt(0).toString(16).toUpperCase())}export function buildStitcherMasterUrl(e){const{stitcherUrl:i,streamId:o,maxBitrate:n,extraParams:s}=e;if(!i)throw new Error("buildStitcherMasterUrl: stitcherUrl is required");if(!o)throw new Error("buildStitcherMasterUrl: streamId is required");const c=i.indexOf("#"),a=-1===c?i:i.slice(0,c),d=[`stream_id=${t(o)}`];if(void 0!==n&&d.push(`max_bitrate=${t(String(n))}`),s)for(const[e,i]of r(s))d.push(`${t(e)}=${t(i)}`);const u=a.includes("?")?"&":"?";return`${a}${u}${d.join("&")}`}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{debugLog as e}from"../diagnostics/debugLog";import{
|
|
1
|
+
import{debugLog as e}from"../diagnostics/debugLog";import{AdError as t}from"../types/AdError";import{VendorAdError as s}from"../types/VendorAdError";import{classifyImaAdError as a}from"./classifyImaAdError";import{html5ImaErrorName as r}from"./html5ImaErrorNames";export function isImaCsaiSdkAvailable(){return"undefined"!=typeof google&&void 0!==google.ima&&void 0!==google.ima.AdsLoader&&void 0!==google.ima.AdDisplayContainer}export class VastAdManager{constructor(e,t,s=!1){this.adContainer=e,this.adVideoElement=t,this.adDisplayContainer=null,this.adsLoader=null,this.adsManager=null,this.callbacks={},this.preloadResolve=null,this.preloadReject=null,this.startResolve=null,this.startReject=null,this.pendingMuted=!1,this.settled=!1,this.preloaded=!1,this.started=!1,this.currentAdDurationSec=null,this.debug=s}setCallbacks(e){this.callbacks=e}resize(){this.adsManager&&(this.adsManager.resize(this.slotWidth(),this.slotHeight(),google.ima.ViewMode.NORMAL),this.log("VAST AdsManager resized to",this.slotWidth(),"x",this.slotHeight()))}preloadVast(e,s){return this.reset(),isImaCsaiSdkAvailable()?new Promise((t,a)=>{this.preloadResolve=t,this.preloadReject=a;try{this.setupContainerAndLoader();const t=new google.ima.AdsRequest;t.adTagUrl=e,t.linearAdSlotWidth=this.slotWidth(),t.linearAdSlotHeight=this.slotHeight(),t.setAdWillAutoPlay(!0),this.pendingMuted=s?.muted??!1,t.setAdWillPlayMuted(this.pendingMuted),this.log("Preloading VAST ads:",e),this.adsLoader.requestAds(t)}catch(e){this.rejectPreload(e instanceof Error?e:new Error(String(e)))}}):Promise.reject(new t('Google IMA client-side SDK not found. Include <script src="https://imasdk.googleapis.com/js/sdkloader/ima3.js"><\/script> in your page.',"DA-VAST-IMA-SDK-MISSING"))}startPreloaded(){return new Promise((e,t)=>{if(this.adsManager&&this.preloaded&&!this.started){this.started=!0,this.settled=!1,this.startResolve=e,this.startReject=t;try{this.resize(),this.adsManager.start(),this.log("VAST AdsManager started")}catch(e){this.failStart(e instanceof Error?e:new Error(String(e)))}}else t(new Error("No preloaded VAST AdsManager; call preloadVast() first"))})}hasPreloadedManager(){return null!==this.adsManager&&this.preloaded&&!this.started&&!this.settled}setMuted(e){this.pendingMuted=e,this.adsManager?.setVolume(e?0:1)}setVolume(e){this.pendingMuted=e<=0,this.adsManager?.setVolume(e)}playVast(e,t){return this.preloadVast(e,t).then(()=>this.startPreloaded())}setupContainerAndLoader(){this.adDisplayContainer=new google.ima.AdDisplayContainer(this.adContainer,this.adVideoElement),this.adDisplayContainer.initialize(),this.adsLoader=new google.ima.AdsLoader(this.adDisplayContainer),this.adsLoader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,e=>this.onAdsManagerLoaded(e)),this.adsLoader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR,e=>this.onAdError(e))}onAdsManagerLoaded(e){try{const t=new google.ima.AdsRenderingSettings;t.restoreCustomPlaybackStateOnAdBreakComplete=!0,t.enablePreloading=!0;const s=e.getAdsManager(this.adVideoElement,t);this.adsManager=s,this.wireManagerEvents(s),this.pendingMuted&&s.setVolume(0),s.init(this.slotWidth(),this.slotHeight(),google.ima.ViewMode.NORMAL),this.preloaded=!0,this.resolvePreload(),this.log("VAST AdsManager initialized and ready")}catch(e){this.rejectPreload(e instanceof Error?e:new Error(String(e)))}}wireManagerEvents(e){const t=google.ima.AdEvent.Type;e.addEventListener(t.STARTED,e=>{this.resize();const t=e.getAd?.(),s=t?.getDuration?.();this.currentAdDurationSec="number"==typeof s&&Number.isFinite(s)&&s>0?s:null;const a=t?.getAdPodInfo?.()?.getAdPosition?.();this.callbacks.onAdStarted?.("number"==typeof a&&Number.isFinite(a)&&a>=1?Math.floor(a):void 0)}),e.addEventListener(t.AD_PROGRESS,()=>this.emitAdProgress()),e.addEventListener(t.FIRST_QUARTILE,()=>this.callbacks.onAdFirstQuartile?.()),e.addEventListener(t.MIDPOINT,()=>this.callbacks.onAdMidpoint?.()),e.addEventListener(t.THIRD_QUARTILE,()=>this.callbacks.onAdThirdQuartile?.()),e.addEventListener(t.CONTENT_PAUSE_REQUESTED,()=>this.callbacks.onContentPauseRequested?.()),e.addEventListener(t.CONTENT_RESUME_REQUESTED,()=>this.callbacks.onContentResumeRequested?.()),e.addEventListener(t.ALL_ADS_COMPLETED,()=>this.succeedStart()),e.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR,e=>this.onAdError(e))}emitAdProgress(){if(!this.callbacks.onAdProgress||!this.adsManager)return;const e=this.currentAdDurationSec;if(null==e)return;const t=this.adsManager.getRemainingTime();if(!Number.isFinite(t)||t<0)return;const s=Math.max(0,Math.min(e,e-t));this.callbacks.onAdProgress(s,e)}onAdError(e){const i=e?.getError?.(),o=i?.getMessage?.()??"Unknown IMA CSAI error",d=i?.getErrorCode?.();this.log("VAST IMA error:",o);const n="number"==typeof d?new s(o,String(d),a(r(d))):new t(o,"DA-VAST-IMA-ERROR");this.startReject?this.failStart(n):this.preloadReject&&this.rejectPreload(n)}succeedStart(){this.settled||(this.settled=!0,this.log("VAST playout complete"),this.startResolve?.(),this.clearStartPromises(),this.teardownManager())}failStart(e){this.settled||(this.settled=!0,this.startReject?.(e),this.clearStartPromises(),this.teardownManager())}resolvePreload(){this.preloadResolve?.(),this.clearPreloadPromises()}rejectPreload(e){this.preloadReject?.(e),this.clearPreloadPromises(),this.teardownManager()}clearPreloadPromises(){this.preloadResolve=null,this.preloadReject=null}clearStartPromises(){this.startResolve=null,this.startReject=null}slotWidth(){return this.adVideoElement.clientWidth||640}slotHeight(){return this.adVideoElement.clientHeight||360}teardownManager(){this.adsManager&&(this.adsManager.destroy(),this.adsManager=null),this.adsLoader&&(this.adsLoader.destroy(),this.adsLoader=null),this.adDisplayContainer&&(this.adDisplayContainer.destroy(),this.adDisplayContainer=null)}reset(){this.teardownManager(),this.settled=!1,this.preloaded=!1,this.started=!1,this.pendingMuted=!1,this.currentAdDurationSec=null,this.clearPreloadPromises(),this.clearStartPromises()}destroy(){this.reset(),this.callbacks={}}log(...t){this.debug&&e("[VastAdManager]",...t)}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AssetType as t}from"../../types/BreakManifest";export class AdPlayerEvents{constructor(t,e){this.state=t,this.deps=e}recordAdProgress(t){!Number.isFinite(t)||t<=0||(this.deps.onGamPodAdProgress(t),t>this.state.currentAssetElapsedSec&&(this.state.currentAssetElapsedSec=t))}settleAssetProgress(){let t=this.state.currentAssetElapsedSec;if(t<=0){const e=this.state.currentAsset?.duration;"number"==typeof e&&Number.isFinite(e)&&e>0&&(t=e)}this.state.adSecondsPlayedThisBreak+=t,this.state.currentAssetElapsedSec=0}reportAdProgress(e){if(this.state.isPlaying&&this.state.currentBreak&&this.state.currentAsset&&(this.recordAdProgress(e.currentTime),this.deps.maybePrepositionContentForResume(),this.state.currentBreak&&this.deps.maybeCatchUpContentForResume(this.state.currentBreak),this.state.callbacks?.onAdTimeUpdate(this.state.currentBreak,this.state.currentAsset,e.currentTime,e.duration),this.state.currentAsset.type===t.STATIC&&e.duration>0)){const t=e.currentTime/e.duration,s=this.deps.getStaticQuartilesFired(),r=this.deps.getGamEventCallbacks();t>=.25&&!s.has("first")&&(s.add("first"),r.onAdFirstQuartile?.(this.state.currentBreak,this.state.currentAsset)),t>=.5&&!s.has("mid")&&(s.add("mid"),r.onAdMidpoint?.(this.state.currentBreak,this.state.currentAsset)),t>=.75&&!s.has("third")&&(s.add("third"),r.onAdThirdQuartile?.(this.state.currentBreak,this.state.currentAsset))}}setupEventListeners(){const t=this.deps.getAdPlayer();if(!t)return;t.on("ended",()=>{this.deps.onAdEnded()}),t.on("timedmetadata",t=>{t&&this.deps.processTimedMetadata(t)}),t.on("error",t=>{this.onAdError(this.deps.toAdError(t))}),t.on("timeupdate",()=>this.reportAdProgress(t)),t.on("waiting",()=>{this.state.isPlaying&&this.state.currentBreak&&this.state.currentAsset&&this.state.callbacks?.onAdWaiting(this.state.currentBreak,this.state.currentAsset)}),t.on("playing",()=>{if(this.state.isPlaying&&this.state.currentBreak&&this.state.currentAsset)
|
|
1
|
+
import{AssetType as t}from"../../types/BreakManifest";export class AdPlayerEvents{constructor(t,e){this.state=t,this.deps=e}recordAdProgress(t){!Number.isFinite(t)||t<=0||(this.deps.onGamPodAdProgress(t),t>this.state.currentAssetElapsedSec&&(this.state.currentAssetElapsedSec=t))}settleAssetProgress(){let t=this.state.currentAssetElapsedSec;if(t<=0){const e=this.state.currentAsset?.duration;"number"==typeof e&&Number.isFinite(e)&&e>0&&(t=e)}this.state.adSecondsPlayedThisBreak+=t,this.state.currentAssetElapsedSec=0}reportAdProgress(e){if(this.state.isPlaying&&this.state.currentBreak&&this.state.currentAsset&&(this.recordAdProgress(e.currentTime),this.deps.maybePrepositionContentForResume(),this.state.currentBreak&&this.deps.maybeCatchUpContentForResume(this.state.currentBreak),this.state.callbacks?.onAdTimeUpdate(this.state.currentBreak,this.state.currentAsset,e.currentTime,e.duration),this.state.currentAsset.type===t.STATIC&&e.duration>0)){const t=e.currentTime/e.duration,s=this.deps.getStaticQuartilesFired(),r=this.deps.getGamEventCallbacks();t>=.25&&!s.has("first")&&(s.add("first"),r.onAdFirstQuartile?.(this.state.currentBreak,this.state.currentAsset)),t>=.5&&!s.has("mid")&&(s.add("mid"),r.onAdMidpoint?.(this.state.currentBreak,this.state.currentAsset)),t>=.75&&!s.has("third")&&(s.add("third"),r.onAdThirdQuartile?.(this.state.currentBreak,this.state.currentAsset))}}setupEventListeners(){const t=this.deps.getAdPlayer();if(!t)return;t.on("ended",()=>{this.deps.onAdEnded()}),t.on("timedmetadata",t=>{t&&this.deps.processTimedMetadata(t)}),t.on("error",t=>{this.onAdError(this.deps.toAdError(t))}),t.on("timeupdate",()=>this.reportAdProgress(t)),t.on("waiting",()=>{this.state.isPlaying&&this.state.currentBreak&&this.state.currentAsset&&this.state.callbacks?.onAdWaiting(this.state.currentBreak,this.state.currentAsset)}),t.on("playing",()=>{if(this.state.isPlaying&&this.state.currentBreak&&this.state.currentAsset&&!t.paused){if(this.state.startPlaybackCutoff?.(),this.state.firstFrameResolver)return this.deps.revealFirstFrame(),this.state.firstFrameResolver(),void this.state.callbacks?.onAdPlaying(this.state.currentBreak,this.state.currentAsset);this.state.callbacks?.onAdPlaying(this.state.currentBreak,this.state.currentAsset)}});const e=()=>{const t=this.deps.getAdPlayer();if(this.deps.getSyncing()||!t)return;const e=this.deps.getAudioFocus();e?"ad"===e?this.deps.notifyVolumeChange():(this.deps.setSyncing(!0),t.muted=!0,t.volume=0,this.deps.setSyncing(!1)):this.state.isPlaying&&(this.deps.setSyncing(!0),this.deps.getContentPlayer().muted=t.muted,this.deps.getContentPlayer().volume=t.volume,this.deps.setSyncing(!1),this.deps.notifyVolumeChange())};this.deps.setAdVolumeChangeHandler(e),t.on("volumechange",e);const s=()=>{const t=this.deps.getAdPlayer();if(this.deps.getSyncing()||!t)return;const e=this.deps.getAudioFocus();e?"content"===e?this.deps.notifyVolumeChange():(this.deps.setSyncing(!0),this.deps.getContentPlayer().muted=!0,this.deps.setSyncing(!1)):(this.deps.setSyncing(!0),t.muted=this.deps.getContentPlayer().muted,t.volume=this.deps.getContentPlayer().volume,this.deps.setSyncing(!1),this.deps.notifyVolumeChange())};this.deps.setContentVolumeHandler(s),this.deps.getContentPlayer().on("volumechange",s)}onAdError(t){const e=this.deps.getSequencer();if(this.state.currentBreak&&e){if(this.state.firstFrameRejector){const e=this.state.firstFrameRejector;this.deps.clearFirstFrameResolver(),e(t)}this.deps.log("Ad error:",t.message),this.deps.setPendingAdError(t),this.deps.drive(e.onOutcome({kind:"asset-errored"}))}}}
|
|
@@ -16,6 +16,7 @@ export interface AdPlayerState {
|
|
|
16
16
|
contentPaused: boolean;
|
|
17
17
|
callbacks: AdPlayerCallbacks | null;
|
|
18
18
|
durationTimer: ReturnType<typeof setTimeout> | null;
|
|
19
|
+
startPlaybackCutoff: (() => void) | null;
|
|
19
20
|
effectiveBreakDurationSec: number | null;
|
|
20
21
|
adInsertionType: AdInsertionType | undefined;
|
|
21
22
|
breakTimebase: Timebase | null;
|
|
@@ -57,9 +58,22 @@ export interface AdPlayerState {
|
|
|
57
58
|
savedContentEdgeDistance: number | null;
|
|
58
59
|
earlyReturnResumeOffsetSec: number | null;
|
|
59
60
|
contentPositionAtBreakStart: number;
|
|
61
|
+
/**
|
|
62
|
+
* Whether this break's anchor is the in-stream cue rather than the pause position — i.e.
|
|
63
|
+
* whether the content under the ad is known slate of exactly the advertised duration.
|
|
64
|
+
*/
|
|
65
|
+
resumeAnchorIsCue: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* The seekable end as the engine reported it at break start, captured with the anchor so the
|
|
68
|
+
* two are comparable. Their difference is the cushion the resume has to work with: a playhead
|
|
69
|
+
* riding its engine's seekable end has none, and any under-published second then lands short.
|
|
70
|
+
*/
|
|
71
|
+
resumeAnchorSeekableEnd: number | null;
|
|
60
72
|
resumePrepositionedTo: number | null;
|
|
61
73
|
resumePrepositionSettle: ReturnType<typeof setTimeout> | null;
|
|
62
74
|
resumeCatchupActive: boolean;
|
|
75
|
+
/** Catch-up started this break; outlives `resumeCatchupActive`, which the cut clears first. */
|
|
76
|
+
resumeCatchupRan: boolean;
|
|
63
77
|
lastResumeAlignRemainingSec: number;
|
|
64
78
|
resumeAlignBlockedDiagnosed: boolean;
|
|
65
79
|
lastResumeSafeEnd: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function invalidateMediaPreload(e){return e.preparedMedia=null,++e.preloadGeneration}export function createAdPlayerState(){return{currentBreak:null,currentAsset:null,isPlaying:!1,contentPaused:!1,callbacks:null,durationTimer:null,effectiveBreakDurationSec:null,adInsertionType:void 0,breakTimebase:null,adBreakCutSafetyMarginSec:0,detectedDeviceType:void 0,sessionAssetParameters:void 0,updatedAssetParameters:void 0,manifestAssetParameters:void 0,sessionAssetParameterMacros:{},pushedAssetParameters:null,gamStreamManager:null,gamPodMode:"none",gamPodTracker:null,gamPodAsset:null,earlyGamPodAdStart:null,withheldPodAdBegin:null,gamConfig:void 0,gamInitPromise:null,currentGamIdentity:void 0,playerContainer:null,stage:null,contentVideoElement:null,adContainer:null,adMediaContainer:null,adPlayer:null,companionElement:null,overlayImageEl:null,isContentFullscreen:!1,trackedContentVideo:null,fullscreenEnterHandler:null,fullscreenExitHandler:null,contentPictureInPicture:!1,pipTransferredToAd:!1,pipAdoptedForBreak:!1,sharedAdClaimActive:!1,savedContentSrc:null,savedContentTime:0,savedContentLive:!1,savedContentEdgeDistance:null,earlyReturnResumeOffsetSec:null,contentPositionAtBreakStart:0,resumePrepositionedTo:null,resumePrepositionSettle:null,resumeCatchupActive:!1,lastResumeAlignRemainingSec:Number.POSITIVE_INFINITY,resumeAlignBlockedDiagnosed:!1,lastResumeSafeEnd:Number.NEGATIVE_INFINITY,resumeSawSeekDone:!1,resumeBestSawMarginSec:Number.NEGATIVE_INFINITY,resumeAlignTicks:0,resumeSawSteps:[],continueContentDuringBreak:!1,continueQualityOverrideApplied:!1,continueContentDuringBreakActive:!1,keepContentPlayingHandler:null,continuePlayoutStartWallMs:0,continuePlayoutTicker:null,continueRateWritten:null,continueRateWrittenAtMs:0,continueRateHonoured:!0,continueMaxAbsDriftSec:0,continueCorrections:[],continueDriftUnrecoverable:!1,continueRefusalReported:!1,contentMutedBeforeCatchup:null,resumeAlignCorrectionsMs:[],resumeLandedProbe:null,adSecondsPlayedThisBreak:0,currentAssetElapsedSec:0,preparedMedia:null,preloadGeneration:0,firstFrameGateActive:!1,firstFrameGateShown:!1,firstFrameResolver:null,firstFrameRejector:null,firstFrameTimeout:null,adStartDeadlineMs:null,adStartBudgetMs:0,vastAdManager:null}}
|
|
1
|
+
export function invalidateMediaPreload(e){return e.preparedMedia=null,++e.preloadGeneration}export function createAdPlayerState(){return{currentBreak:null,currentAsset:null,isPlaying:!1,contentPaused:!1,callbacks:null,durationTimer:null,startPlaybackCutoff:null,effectiveBreakDurationSec:null,adInsertionType:void 0,breakTimebase:null,adBreakCutSafetyMarginSec:0,detectedDeviceType:void 0,sessionAssetParameters:void 0,updatedAssetParameters:void 0,manifestAssetParameters:void 0,sessionAssetParameterMacros:{},pushedAssetParameters:null,gamStreamManager:null,gamPodMode:"none",gamPodTracker:null,gamPodAsset:null,earlyGamPodAdStart:null,withheldPodAdBegin:null,gamConfig:void 0,gamInitPromise:null,currentGamIdentity:void 0,playerContainer:null,stage:null,contentVideoElement:null,adContainer:null,adMediaContainer:null,adPlayer:null,companionElement:null,overlayImageEl:null,isContentFullscreen:!1,trackedContentVideo:null,fullscreenEnterHandler:null,fullscreenExitHandler:null,contentPictureInPicture:!1,pipTransferredToAd:!1,pipAdoptedForBreak:!1,sharedAdClaimActive:!1,savedContentSrc:null,savedContentTime:0,savedContentLive:!1,savedContentEdgeDistance:null,earlyReturnResumeOffsetSec:null,contentPositionAtBreakStart:0,resumeAnchorIsCue:!1,resumeAnchorSeekableEnd:null,resumePrepositionedTo:null,resumePrepositionSettle:null,resumeCatchupActive:!1,resumeCatchupRan:!1,lastResumeAlignRemainingSec:Number.POSITIVE_INFINITY,resumeAlignBlockedDiagnosed:!1,lastResumeSafeEnd:Number.NEGATIVE_INFINITY,resumeSawSeekDone:!1,resumeBestSawMarginSec:Number.NEGATIVE_INFINITY,resumeAlignTicks:0,resumeSawSteps:[],continueContentDuringBreak:!1,continueQualityOverrideApplied:!1,continueContentDuringBreakActive:!1,keepContentPlayingHandler:null,continuePlayoutStartWallMs:0,continuePlayoutTicker:null,continueRateWritten:null,continueRateWrittenAtMs:0,continueRateHonoured:!0,continueMaxAbsDriftSec:0,continueCorrections:[],continueDriftUnrecoverable:!1,continueRefusalReported:!1,contentMutedBeforeCatchup:null,resumeAlignCorrectionsMs:[],resumeLandedProbe:null,adSecondsPlayedThisBreak:0,currentAssetElapsedSec:0,preparedMedia:null,preloadGeneration:0,firstFrameGateActive:!1,firstFrameGateShown:!1,firstFrameResolver:null,firstFrameRejector:null,firstFrameTimeout:null,adStartDeadlineMs:null,adStartBudgetMs:0,vastAdManager:null}}
|
|
@@ -3,6 +3,10 @@ import { Asset, Break, BreakVariant, StaticAsset, VastAsset } from '../../types/
|
|
|
3
3
|
import type { ResolvedPreloadMode } from '../detectPreloadMode';
|
|
4
4
|
import { type AdPlayerState } from './AdPlayerState';
|
|
5
5
|
import type { Clock } from '../BreakScheduler';
|
|
6
|
+
/** A stalled ad load gets one second load() this far into the ad-start budget. */
|
|
7
|
+
export declare const AD_LOAD_RETRY_AFTER_MS = 2000;
|
|
8
|
+
/** True when the ad element has produced nothing since load() — no metadata and no buffered media. */
|
|
9
|
+
export declare function adLoadShowsNoProgress(video: HTMLVideoElement | null | undefined): boolean;
|
|
6
10
|
export interface AdPreloaderDeps {
|
|
7
11
|
state: AdPlayerState;
|
|
8
12
|
clock: Clock;
|
|
@@ -46,7 +50,11 @@ export declare class AdPreloader {
|
|
|
46
50
|
revealFirstFrame(): void;
|
|
47
51
|
armAdStartBudget(asset: Asset): void;
|
|
48
52
|
remainingAdStartBudgetMs(): number;
|
|
49
|
-
loadWithinBudget(
|
|
53
|
+
loadWithinBudget(startLoad: () => Promise<void>, context: {
|
|
54
|
+
breakId: string;
|
|
55
|
+
assetId: string;
|
|
56
|
+
uri: string;
|
|
57
|
+
}): Promise<boolean>;
|
|
50
58
|
waitForFirstFrame(): Promise<void>;
|
|
51
59
|
clearFirstFrame(reason?: string): void;
|
|
52
60
|
clearFirstFrameResolver(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AssetType as e,BreakFormat as t,MediaType as s,Vendor as
|
|
1
|
+
import{AssetType as e,BreakFormat as t,MediaType as s,Vendor as r,isVastAsset as a,isVendorAsset as i}from"../../types/BreakManifest";import{AUX_FETCH_TIMEOUT_MS as d,fetchWithTimeout as o}from"../fetchWithTimeout";import{resolveVastAdmission as n}from"../resolveVastAdmission";import{isImaCsaiSdkAvailable as l,VastAdManager as p}from"../VastAdManager";import{invalidateMediaPreload as h}from"./AdPlayerState";import{AdError as m}from"../../types/AdError";export const AD_LOAD_RETRY_AFTER_MS=2e3;export function adLoadShowsNoProgress(e){return!e||0===e.readyState&&0===e.buffered.length}export class AdPreloader{constructor(e){this.deps=e,this.warmedBreakIds=new Set}classifyCreative(e){const t=(e.split(/[?#]/)[0]??"").toLowerCase();return t.endsWith(".m3u8")||t.endsWith(".mpd")?"stream":/\.(mp4|m4v|m4a|webm|mov|ogg|ogv|mp3)$/.test(t)?"progressive":"unknown"}diagnosePreloadPath(e,t,s){const r=this.classifyCreative(t);this.deps.diagnose("DA-PRELOAD-PATH",`Ad preload path: ${s} (${r} creative)`,{breakId:e,adPreload:this.deps.preloadMode,path:s,creative:r})}async preload(r){if(this.deps.isPlaying())return void this.deps.log("Preload skipped: ad already playing");const i=h(this.deps.state),d=this.deps.getAdPlayer();if("none"===this.deps.preloadMode){const t=this.deps.getAssets(r)[0],s=t&&t.type===e.STATIC?this.deps.resolveUri(t.uri)??"":"";return this.diagnosePreloadPath(r.id,s,"none"),void this.deps.log('Preload skipped: adPreload "none"')}if("shared-element"===this.deps.effectiveInsertionMode()){const s=this.deps.getVariant(r);if(s&&s.format!==t.LSHAPE_CONTENT){const t=this.deps.getAssets(r)[0];if(t&&t.type===e.STATIC){const e=this.deps.resolveUri(t.uri);e&&await this.warmCache([e])}}return}const o=this.deps.getAssets(r);if(0===o.length)return void this.deps.log("No assets to preload");this.preloadCompanion(r);const n=this.deps.getVariant(r);if(n?.format===t.LSHAPE_CONTENT)return;if(o[0].mediaType===s.IMAGE){const e=await this.deps.resolveAssetUri(o[0],r.duration);if(e){(new Image).src=e,this.deps.log("Preloading overlay image:",e)}return}if(a(o[0]))return void await this.preloadVastAsset(o[0],r);const l=await this.deps.resolveAssetUri(o[0],r.duration);if(l){if(d&&this.ownsPreload(i,d))if("single-decoder"!==this.deps.preloadMode){this.deps.log("Preloading ad (parallel):",l),this.diagnosePreloadPath(r.id,l,"parallel");try{if(await d.load(l),!this.ownsPreload(i,d))return;this.deps.state.preparedMedia={breakId:r.id,assetId:o[0].id,uri:l,player:d},this.deps.log("Preload complete for break:",r.id)}catch(e){this.deps.log("Preload failed (will load on demand):",e)}}else{if(this.deps.log("Preloading ad (single-decoder, detached):",l),this.diagnosePreloadPath(r.id,l,"single-decoder"),await this.warmCache([l]),!this.ownsPreload(i,d))return;try{await(d.preload?.(l))}catch(e){this.deps.log("Detached prefetch failed (will load on demand):",e)}}}else this.deps.log("No valid URI for preload")}ownsPreload(e,t){return e===this.deps.state.preloadGeneration&&!this.deps.isPlaying()&&t===this.deps.getAdPlayer()}async preloadVastAsset(e,s){const r=this.deps.getVariant(s),a=r?.format??t.SINGLE;if(!n({format:a,ssai:!1}).admitted)return void this.deps.log("VAST preload skipped: format not supported",a);if(!l())return void this.deps.log("VAST preload skipped: IMA client-side SDK unavailable");const i=this.deps.getAdPlayer(),d=this.deps.getAdContainer();if(!i||!d)return void this.deps.log("VAST preload skipped: ad player not initialized");const o=i.videoElement;if(!o)return void this.deps.log("VAST preload skipped: no ad video element");const h=this.deps.buildVastTagUrl(e,s);if(h){this.deps.state.vastAdManager||(this.deps.state.vastAdManager=new p(d,o,this.deps.debug)),this.deps.log("Preloading VAST asset via IMA CSAI:",h);try{await this.deps.state.vastAdManager.preloadVast(h,{muted:i.muted}),this.deps.log("VAST preload complete for break:",s.id)}catch(t){const r=t instanceof Error?t:new Error(String(t));this.deps.log("VAST preload failed (will load on demand):",r.message),this.deps.diagnose("DA-PRELOAD-FAILED",r.message,{breakId:s.id,assetId:e.id})}}else this.deps.log("No valid VAST tag URL for preload")}preloadChainedSuccessor(e){const t=this.deps.resolveChainedSuccessor(e);t&&this.preloadNext(t)}clearWarmedBreaks(){this.warmedBreakIds.clear()}async preloadNext(s){if(this.warmedBreakIds.has(s.id))return;this.preloadCompanion(s);const r=this.deps.getVariant(s);if(!r||r.format===t.LSHAPE_CONTENT)return;const a=this.deps.getAssets(s)[0];if(!a||a.type!==e.STATIC)return void this.deps.log("Chained successor first asset not static; skipping media warm:",s.id);const i=this.deps.resolveUri(a.uri);if(i){this.warmedBreakIds.add(s.id),this.deps.log("Warming chained successor media:",s.id,i),await this.warmCache([i]);try{await(this.deps.getAdPlayer()?.preload?.(i))}catch(e){this.deps.log("Chained prefetch failed (will load on demand):",e)}}}revealFirstFrame(){if(!this.deps.state.firstFrameGateActive||this.deps.state.firstFrameGateShown)return;const e=this.deps.getCurrentBreak();if(!e)return;this.deps.state.firstFrameGateShown=!0,this.deps.show();const t=this.deps.getVariant(e);t&&this.deps.reapplyAdContainerLayout(t),this.deps.onBreakVisible(e)}armAdStartBudget(e){const t=1e3*((this.deps.state.effectiveBreakDurationSec??this.deps.state.currentBreak?.duration??0)+this.deps.state.adBreakCutSafetyMarginSec),s=i(e)&&e.vendor===r.GAM?this.deps.gamPodAdStartBudgetMs:this.deps.adStartBudgetMs,a=Math.max(Math.min(t-100,s),this.deps.minAdStartBudgetMs);this.deps.state.adStartBudgetMs=a,this.deps.state.adStartDeadlineMs=this.deps.clock.now()+a}remainingAdStartBudgetMs(){return Math.max(0,(this.deps.state.adStartDeadlineMs??this.deps.clock.now())-this.deps.clock.now())}loadWithinBudget(e,t){const s=this.deps.state.preloadGeneration,r=this.remainingAdStartBudgetMs(),a=this.deps.clock.now();return new Promise((i,d)=>{let o=!1,n=!1;const l=e=>{o||(o=!0,clearTimeout(p),null!==h&&clearTimeout(h),e.ok?i(!0):d(e.error instanceof Error?e.error:new Error(String(e.error))))},p=setTimeout(()=>{s===this.deps.state.preloadGeneration&&this.deps.onAdError(new m("Ad load timeout","DA-AD-START-TIMEOUT")),o||(o=!0,null!==h&&clearTimeout(h),i(!1))},r);let h=null;r>2e3&&(h=setTimeout(()=>{if(o||s!==this.deps.state.preloadGeneration)return;const r=this.deps.clock.now()-a,i=this.deps.getAdPlayer()?.videoElement;adLoadShowsNoProgress(i)?(n=!0,this.deps.log(`Ad load for ${t.assetId} stalled after ${r}ms; retrying once`),this.deps.diagnose("DA-AD-LOAD-RETRIED",`Ad load for ${t.assetId} in break ${t.breakId} had not settled after ${r}ms; issued a second load()`,{breakId:t.breakId,assetId:t.assetId,uri:t.uri,elapsedMs:r,remainingBudgetMs:this.remainingAdStartBudgetMs()}),e().then(()=>l({ok:!0}),e=>l({ok:!1,error:e}))):this.deps.log(`Ad load for ${t.assetId} still pending after ${r}ms but the element is progressing (readyState=${i?.readyState}, buffered=${i?.buffered.length}); no retry`)},2e3)),e().then(()=>l({ok:!0}),e=>{n||l({ok:!1,error:e})})})}async waitForFirstFrame(){return new Promise((e,t)=>{this.deps.state.firstFrameResolver=()=>{this.clearFirstFrameResolver(),e()},this.deps.state.firstFrameRejector=e=>{this.clearFirstFrameResolver(),t(e)},this.deps.state.firstFrameTimeout=setTimeout(()=>{this.deps.onAdError(new m("First frame timeout","DA-AD-START-TIMEOUT"))},this.remainingAdStartBudgetMs())})}clearFirstFrame(e="Break ended before first frame"){if(this.deps.state.adStartDeadlineMs=null,this.deps.state.adStartBudgetMs=0,this.deps.state.firstFrameTimeout&&(clearTimeout(this.deps.state.firstFrameTimeout),this.deps.state.firstFrameTimeout=null),this.deps.state.firstFrameRejector){const t=this.deps.state.firstFrameRejector;this.deps.state.firstFrameResolver=null,this.deps.state.firstFrameRejector=null,t(new Error(e))}}clearFirstFrameResolver(){this.deps.state.adStartDeadlineMs=null,this.deps.state.adStartBudgetMs=0,this.deps.state.firstFrameTimeout&&(clearTimeout(this.deps.state.firstFrameTimeout),this.deps.state.firstFrameTimeout=null),this.deps.state.firstFrameResolver=null,this.deps.state.firstFrameRejector=null}preloadCompanion(s){const r=this.deps.getCompanionVariant(s);if(!r)return;if(r.format===t.LSHAPE_CONTENT){const t=r.assets[0];if(!t||t.type!==e.STATIC)return;const s=this.deps.resolveUri(t.uri);if(!s)return;return(new Image).src=s,void this.deps.log("Preloading lshape_content backdrop:",s)}if(r.format!==t.DOUBLE&&r.format!==t.LSHAPE_AD)return;const a=r.assets[0]?.companion;if(!a||a.type!==e.STATIC)return;const i=this.deps.resolveUri(a.uri);if(!i)return;(new Image).src=i,this.deps.log("Preloading companion:",i)}async warmCache(e){"function"==typeof fetch&&await Promise.allSettled(e.map(e=>o(e,{mode:"no-cors"},d).catch(()=>{})))}}
|
|
@@ -37,10 +37,14 @@ export declare class AdStage {
|
|
|
37
37
|
private contentVideoGeometryHandler;
|
|
38
38
|
private contentVideoMutationObserver;
|
|
39
39
|
private resizeObserver;
|
|
40
|
+
private resizePoll;
|
|
40
41
|
private companionRemoveTimer;
|
|
41
42
|
private adFadeTimer;
|
|
43
|
+
private preparedLease;
|
|
44
|
+
private unsubscribeGeometry;
|
|
42
45
|
constructor(deps: AdStageDeps);
|
|
43
46
|
setupOverlay(): void;
|
|
47
|
+
private setupMediaLayer;
|
|
44
48
|
private refreshStageGeometry;
|
|
45
49
|
private rebindContentVideoGeometryListener;
|
|
46
50
|
private updateStageGeometry;
|
|
@@ -53,5 +57,7 @@ export declare class AdStage {
|
|
|
53
57
|
clearOverlayImage(): void;
|
|
54
58
|
show(): void;
|
|
55
59
|
hide(): void;
|
|
60
|
+
restoreContent(createdBySDK: boolean, originalStyle: string): boolean;
|
|
61
|
+
private releasePreparedPresentation;
|
|
56
62
|
destroy(): void;
|
|
57
63
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AssetType as e,BreakFormat as t}from"../../types/BreakManifest";const s=16/9;export class AdStage{constructor(e){this.deps=e,this.contentVideoGeometryHandler=null,this.contentVideoMutationObserver=null,this.resizeObserver=null,this.companionRemoveTimer=null,this.adFadeTimer=null}setupOverlay(){const e=window.getComputedStyle(this.deps.container);"static"!==e.position&&""!==e.position||(this.deps.container.style.position="relative"),this.deps.setStage(document.createElement("div"));const t=this.deps.getStage();if(!t)return;if(t.className="dolby-stage",t.style.cssText="position:absolute;overflow:hidden;",this.deps.container.appendChild(t),this.contentVideoGeometryHandler=()=>this.refreshStageGeometry(),"undefined"!=typeof MutationObserver&&(this.contentVideoMutationObserver=new MutationObserver(()=>{(this.deps.contentPlayer.videoElement??null)!==this.deps.getContentVideo()&&this.refreshStageGeometry()}),this.contentVideoMutationObserver.observe(this.deps.container,{childList:!0,subtree:!0})),this.resizeObserver=new ResizeObserver(()=>{this.refreshStageGeometry()}),this.resizeObserver.observe(this.deps.container),this.refreshStageGeometry(),this.deps.getPlayerContainer()){const e=this.deps.getPlayerContainer();if(!e)return;t.appendChild(e)}else{const e=document.createElement("div"),s=Array.from(this.deps.container.childNodes).filter(e=>e!==t);for(const t of s)e.appendChild(t);t.appendChild(e),this.deps.setPlayerContainer(e),this.deps.onPlayerContainerCreated()}const s=this.deps.getPlayerContainer();if(!s)return;this.deps.setPlayerContainerOriginalStyle(s.style.cssText),s.style.cssText="position:absolute;top:0;left:0;right:0;bottom:0;transition:top 0.3s ease-in-out,left 0.3s ease-in-out,right 0.3s ease-in-out,bottom 0.3s ease-in-out,opacity 0.3s ease-in-out;",this.deps.setAdContainer(document.createElement("div"));const i=this.deps.getAdContainer();if(!i)return;i.className="dolby-ad-container",i.style.cssText="display:none;position:absolute;top:0;left:0;right:0;bottom:0;z-index:100;background:#000;",this.deps.setAdMediaContainer(document.createElement("div"));const o=this.deps.getAdMediaContainer();o&&(o.style.cssText="display:block;width:100%;height:100%;",i.appendChild(o),t.appendChild(i),this.deps.setAdPlayer(this.deps.createAdAdapter(o)),this.deps.setupEventListeners(),this.deps.log("Ad player overlay initialized"))}refreshStageGeometry(){this.rebindContentVideoGeometryListener(),this.updateStageGeometry(),this.deps.resizeVast()}rebindContentVideoGeometryListener(){const e=this.deps.contentPlayer.videoElement??null,t=e&&"function"==typeof e.addEventListener&&"function"==typeof e.removeEventListener?e:null;t!==this.deps.getContentVideo()&&(this.deps.getContentVideo()&&this.contentVideoGeometryHandler&&(this.deps.getContentVideo()?.removeEventListener("loadedmetadata",this.contentVideoGeometryHandler),this.deps.getContentVideo()?.removeEventListener("resize",this.contentVideoGeometryHandler)),this.deps.setContentVideo(t),t&&this.contentVideoGeometryHandler&&(t.addEventListener("loadedmetadata",this.contentVideoGeometryHandler),t.addEventListener("resize",this.contentVideoGeometryHandler)))}updateStageGeometry(){const e=this.deps.getStage();if(!e)return;const{width:t,height:s}=this.deps.container.getBoundingClientRect();if(0===t||0===s)return;const i=this.getContentAspectRatio();let o,n;t/s>i?(n=s,o=s*i):(o=t,n=t/i);const a=(s-n)/2,r=(t-o)/2;e.style.width=`${o}px`,e.style.height=`${n}px`,e.style.top=`${a}px`,e.style.left=`${r}px`}getContentAspectRatio(){const e=this.deps.contentPlayer.videoElement;if(!e)return s;const{videoWidth:t,videoHeight:i}=e;return!Number.isFinite(t)||!Number.isFinite(i)||t<=0||i<=0?s:t/i}renderLshapeContentBackdrop(t){const s=t.assets[0];if(!s||s.type!==e.STATIC)return;const i=this.deps.resolveUri(s.uri);if(!i)return;const o=document.createElement("img");o.className="dolby-companion",o.src=i,o.style.cssText="position:absolute;top:0;left:0;right:0;bottom:0;z-index:99;object-fit:cover;width:100%;height:100%;opacity:0;transition:opacity 0.3s ease-in-out;";const n=this.deps.getStage();n&&(n.appendChild(o),this.deps.setCompanion(o),requestAnimationFrame(()=>{const e=this.deps.getCompanion();e&&(e.style.opacity="1")}),this.deps.log("Rendered lshape_content backdrop:",i))}reapplyAdContainerLayout(e){const s=this.deps.getAdContainer();if(s){switch(e.format){case t.LSHAPE_AD:s.style.position="absolute",s.style.top="5%",s.style.left="5%",s.style.right="30%",s.style.bottom="30%",s.style.width="",s.style.height="",s.style.zIndex="100";break;case t.DOUBLE:s.style.position="absolute",s.style.top="26.04%",s.style.left="51.04%",s.style.right="1.04%",s.style.bottom="26.04%",s.style.width="",s.style.height="",s.style.zIndex="100"}this.deps.log("reapplyAdContainerLayout: re-stamped adContainer CSS for format:",e.format)}}applyLayout(e){const s=this.deps.getAdContainer(),i=this.deps.getPlayerContainer();if(!s||!i)return;const o="transition:top 0.3s ease-in-out,left 0.3s ease-in-out,right 0.3s ease-in-out,bottom 0.3s ease-in-out,opacity 0.3s ease-in-out;";switch(e.format){case t.SINGLE:s.style.cssText="display:none;opacity:0;position:absolute;top:0;left:0;right:0;bottom:0;z-index:100;background:#000;transition:opacity 0.3s ease-in-out;";break;case t.DOUBLE:i.style.cssText=`position:absolute;top:26.04%;left:1.04%;right:51.04%;bottom:26.04%;z-index:101;${o}`,s.style.cssText="display:none;opacity:0;position:absolute;top:26.04%;left:51.04%;right:1.04%;bottom:26.04%;z-index:100;background:#000;transition:opacity 0.3s ease-in-out;",this.renderCompanion(e.assets,"position:absolute;top:0;left:0;right:0;bottom:0;z-index:99;object-fit:cover;width:100%;height:100%;opacity:0;transition:opacity 0.3s ease-in-out;");break;case t.LSHAPE_AD:i.style.cssText=`position:absolute;top:5%;left:5%;right:30%;bottom:30%;z-index:101;opacity:0;${o}`,s.style.cssText="display:none;opacity:0;position:absolute;top:5%;left:5%;right:30%;bottom:30%;z-index:100;background:#000;transition:opacity 0.3s ease-in-out;",this.renderCompanion(e.assets,"position:absolute;top:0;left:0;right:0;bottom:0;z-index:99;object-fit:cover;width:100%;height:100%;opacity:0;transition:opacity 0.3s ease-in-out;");break;case t.LSHAPE_CONTENT:i.style.top="5%",i.style.left="5%",i.style.right="30%",i.style.bottom="30%",i.style.zIndex="101";break;case t.OVERLAY:{const t=e,i=e=>void 0!==e?100*e+"%":"auto",o=i(t.position.top),n=i(t.position.bottom),a=i(t.position.left),r=i(t.position.right),d=100*t.size.width+"%",l=100*t.size.height+"%",p=t.opacity??1;s.style.cssText=`display:none;position:absolute;top:${o};bottom:${n};left:${a};right:${r};width:${d};height:${l};z-index:100;opacity:${p};`;break}default:s.style.cssText="display:none;position:absolute;top:0;left:0;right:0;bottom:0;z-index:100;background:#000;"}}restoreLayout(e){const s=e===t.DOUBLE||e===t.LSHAPE_AD||e===t.LSHAPE_CONTENT,i=this.deps.getPlayerContainer();if(!i)return;i.style.cssText="position:absolute;top:0;left:0;right:0;bottom:0;"+(s?"z-index:101;":"")+"transition:top 0.3s ease-in-out,left 0.3s ease-in-out,right 0.3s ease-in-out,bottom 0.3s ease-in-out,opacity 0.3s ease-in-out;",this.companionRemoveTimer&&clearTimeout(this.companionRemoveTimer);const o=this.deps.getCompanion();o&&(o.style.opacity="0"),this.companionRemoveTimer=setTimeout(()=>{const e=this.deps.getCompanion();e?.parentElement&&(e.parentElement.removeChild(e),this.deps.setCompanion(null)),this.companionRemoveTimer=null;const t=this.deps.getPlayerContainer();s&&t&&(t.style.zIndex="")},300)}renderCompanion(t,s){const i=t[0]?.companion;if(!i)return;const o=i.type===e.STATIC?this.deps.resolveUri(i.uri):null;if(!o)return;const n=document.createElement("img");n.className="dolby-companion",n.src=o,n.style.cssText=s;const a=this.deps.getStage();a&&(a.appendChild(n),this.deps.setCompanion(n),requestAnimationFrame(()=>{const e=this.deps.getCompanion();e&&(e.style.opacity="1")}))}clearOverlayImage(){const e=this.deps.getImageAssetTimer();e&&(clearTimeout(e),this.deps.setImageAssetTimer(null));const t=this.deps.getOverlayImage();t?.parentElement&&t.parentElement.removeChild(t),this.deps.setOverlayImage(null)}show(){const e=this.deps.getAdContainer();if(!e)return;this.adFadeTimer&&(clearTimeout(this.adFadeTimer),this.adFadeTimer=null);const s=this.deps.getCurrentBreak(),i=s?this.deps.getVariant(s):null;e.style.display="block",i?.format!==t.OVERLAY&&(this.deps.isChaining()?e.style.opacity="1":(e.style.opacity="0",requestAnimationFrame(()=>{const e=this.deps.getAdContainer();e&&(e.style.opacity="1")})))}hide(){const e=this.deps.getAdContainer();if(!e)return;const s=this.deps.getCurrentBreak(),i=s?this.deps.getVariant(s):null;i?.format!==t.OVERLAY?(e.style.opacity="0",this.adFadeTimer=setTimeout(()=>{const e=this.deps.getAdContainer();e&&(e.style.display="none"),this.adFadeTimer=null},300)):e.style.display="none"}destroy(){const e=this.deps.getContentVideo();e&&this.contentVideoGeometryHandler&&(e.removeEventListener("loadedmetadata",this.contentVideoGeometryHandler),e.removeEventListener("resize",this.contentVideoGeometryHandler)),this.contentVideoMutationObserver?.disconnect(),this.resizeObserver?.disconnect(),this.contentVideoMutationObserver=null,this.resizeObserver=null,this.contentVideoGeometryHandler=null,this.companionRemoveTimer&&clearTimeout(this.companionRemoveTimer),this.adFadeTimer&&clearTimeout(this.adFadeTimer)}}
|
|
1
|
+
import{getPreparedPresentation as e}from"./PreparedPresentation";import{AssetType as t,BreakFormat as s}from"../../types/BreakManifest";const i=16/9;export class AdStage{constructor(e){this.deps=e,this.contentVideoGeometryHandler=null,this.contentVideoMutationObserver=null,this.resizeObserver=null,this.resizePoll=null,this.companionRemoveTimer=null,this.adFadeTimer=null,this.preparedLease=null,this.unsubscribeGeometry=null}setupOverlay(){const t=e(this.deps.container);if(t){const e=this.deps.getPlayerContainer();if(e&&e!==t.playerContainer)throw new Error("The prepared content container cannot be replaced");this.preparedLease=t.acquire(),this.deps.setStage(this.preparedLease.stage),this.deps.setPlayerContainer(this.preparedLease.playerContainer),this.unsubscribeGeometry=this.preparedLease.subscribe(()=>this.deps.resizeVast());try{this.setupMediaLayer()}catch(e){const t=this.deps.getAdContainer();throw t?.parentNode?.removeChild(t),this.deps.setAdContainer(null),this.deps.setAdMediaContainer(null),this.unsubscribeGeometry?.(),this.preparedLease.release(),e}return}const s=window.getComputedStyle(this.deps.container);"static"!==s.position&&""!==s.position||(this.deps.container.style.position="relative"),this.deps.setStage(document.createElement("div"));const i=this.deps.getStage();if(!i)return;if(i.className="dolby-stage",i.style.cssText="position:absolute;overflow:hidden;",this.deps.container.appendChild(i),this.contentVideoGeometryHandler=()=>this.refreshStageGeometry(),"undefined"!=typeof MutationObserver&&(this.contentVideoMutationObserver=new MutationObserver(()=>{(this.deps.contentPlayer.videoElement??null)!==this.deps.getContentVideo()&&this.refreshStageGeometry()}),this.contentVideoMutationObserver.observe(this.deps.container,{childList:!0,subtree:!0})),"undefined"!=typeof ResizeObserver)this.resizeObserver=new ResizeObserver(()=>this.refreshStageGeometry()),this.resizeObserver.observe(this.deps.container);else{let e=this.deps.container.getBoundingClientRect();this.resizePoll=setInterval(()=>{const t=this.deps.container.getBoundingClientRect();t.width===e.width&&t.height===e.height||(e=t,this.refreshStageGeometry())},250)}if(this.refreshStageGeometry(),this.deps.getPlayerContainer()){const e=this.deps.getPlayerContainer();if(!e)return;i.appendChild(e)}else{const e=document.createElement("div"),t=Array.from(this.deps.container.childNodes).filter(e=>e!==i);for(const s of t)e.appendChild(s);i.appendChild(e),this.deps.setPlayerContainer(e),this.deps.onPlayerContainerCreated()}const o=this.deps.getPlayerContainer();o&&(this.deps.setPlayerContainerOriginalStyle(o.style.cssText),o.style.cssText="position:absolute;top:0;left:0;right:0;bottom:0;transition:top 0.3s ease-in-out,left 0.3s ease-in-out,right 0.3s ease-in-out,bottom 0.3s ease-in-out,opacity 0.3s ease-in-out;",this.setupMediaLayer())}setupMediaLayer(){const e=this.deps.getStage();if(!e)throw new Error("An ads presentation stage is required");this.deps.setAdContainer(document.createElement("div"));const t=this.deps.getAdContainer();if(!t)return;t.className="dolby-ad-container",t.style.cssText="display:none;position:absolute;top:0;left:0;right:0;bottom:0;z-index:100;background:#000;",this.deps.setAdMediaContainer(document.createElement("div"));const s=this.deps.getAdMediaContainer();s&&(s.style.cssText="display:block;width:100%;height:100%;",t.appendChild(s),e.appendChild(t),this.deps.setAdPlayer(this.deps.createAdAdapter(s)),this.deps.setupEventListeners(),this.deps.log("Ad player overlay initialized"))}refreshStageGeometry(){this.rebindContentVideoGeometryListener(),this.updateStageGeometry(),this.deps.resizeVast()}rebindContentVideoGeometryListener(){const e=this.deps.contentPlayer.videoElement??null,t=e&&"function"==typeof e.addEventListener&&"function"==typeof e.removeEventListener?e:null;t!==this.deps.getContentVideo()&&(this.deps.getContentVideo()&&this.contentVideoGeometryHandler&&(this.deps.getContentVideo()?.removeEventListener("loadedmetadata",this.contentVideoGeometryHandler),this.deps.getContentVideo()?.removeEventListener("resize",this.contentVideoGeometryHandler)),this.deps.setContentVideo(t),t&&this.contentVideoGeometryHandler&&(t.addEventListener("loadedmetadata",this.contentVideoGeometryHandler),t.addEventListener("resize",this.contentVideoGeometryHandler)))}updateStageGeometry(){const e=this.deps.getStage();if(!e)return;const{width:t,height:s}=this.deps.container.getBoundingClientRect();if(0===t||0===s)return;const i=this.getContentAspectRatio();let o,n;t/s>i?(n=s,o=s*i):(o=t,n=t/i);const r=(s-n)/2,a=(t-o)/2;e.style.width=`${o}px`,e.style.height=`${n}px`,e.style.top=`${r}px`,e.style.left=`${a}px`}getContentAspectRatio(){const e=this.deps.contentPlayer.videoElement;if(!e)return i;const{videoWidth:t,videoHeight:s}=e;return!Number.isFinite(t)||!Number.isFinite(s)||t<=0||s<=0?i:t/s}renderLshapeContentBackdrop(e){const s=e.assets[0];if(!s||s.type!==t.STATIC)return;const i=this.deps.resolveUri(s.uri);if(!i)return;const o=document.createElement("img");o.className="dolby-companion",o.src=i,o.style.cssText="position:absolute;top:0;left:0;right:0;bottom:0;z-index:99;object-fit:cover;width:100%;height:100%;opacity:0;transition:opacity 0.3s ease-in-out;";const n=this.deps.getStage();n&&(n.appendChild(o),this.deps.setCompanion(o),requestAnimationFrame(()=>{const e=this.deps.getCompanion();e&&(e.style.opacity="1")}),this.deps.log("Rendered lshape_content backdrop:",i))}reapplyAdContainerLayout(e){const t=this.deps.getAdContainer();if(t){switch(e.format){case s.LSHAPE_AD:t.style.position="absolute",t.style.top="5%",t.style.left="5%",t.style.right="30%",t.style.bottom="30%",t.style.width="",t.style.height="",t.style.zIndex="100";break;case s.DOUBLE:t.style.position="absolute",t.style.top="26.04%",t.style.left="51.04%",t.style.right="1.04%",t.style.bottom="26.04%",t.style.width="",t.style.height="",t.style.zIndex="100"}this.deps.log("reapplyAdContainerLayout: re-stamped adContainer CSS for format:",e.format)}}applyLayout(e){const t=this.deps.getAdContainer(),i=this.deps.getPlayerContainer();if(!t||!i)return;const o="transition:top 0.3s ease-in-out,left 0.3s ease-in-out,right 0.3s ease-in-out,bottom 0.3s ease-in-out,opacity 0.3s ease-in-out;";switch(e.format){case s.SINGLE:t.style.cssText="display:none;opacity:0;position:absolute;top:0;left:0;right:0;bottom:0;z-index:100;background:#000;transition:opacity 0.3s ease-in-out;";break;case s.DOUBLE:i.style.cssText=`position:absolute;top:26.04%;left:1.04%;right:51.04%;bottom:26.04%;z-index:101;${o}`,t.style.cssText="display:none;opacity:0;position:absolute;top:26.04%;left:51.04%;right:1.04%;bottom:26.04%;z-index:100;background:#000;transition:opacity 0.3s ease-in-out;",this.renderCompanion(e.assets,"position:absolute;top:0;left:0;right:0;bottom:0;z-index:99;object-fit:cover;width:100%;height:100%;opacity:0;transition:opacity 0.3s ease-in-out;");break;case s.LSHAPE_AD:i.style.cssText=`position:absolute;top:5%;left:5%;right:30%;bottom:30%;z-index:101;opacity:0;${o}`,t.style.cssText="display:none;opacity:0;position:absolute;top:5%;left:5%;right:30%;bottom:30%;z-index:100;background:#000;transition:opacity 0.3s ease-in-out;",this.renderCompanion(e.assets,"position:absolute;top:0;left:0;right:0;bottom:0;z-index:99;object-fit:cover;width:100%;height:100%;opacity:0;transition:opacity 0.3s ease-in-out;");break;case s.LSHAPE_CONTENT:i.style.top="5%",i.style.left="5%",i.style.right="30%",i.style.bottom="30%",i.style.zIndex="101";break;case s.OVERLAY:{const s=e,i=e=>void 0!==e?100*e+"%":"auto",o=i(s.position.top),n=i(s.position.bottom),r=i(s.position.left),a=i(s.position.right),d=100*s.size.width+"%",l=100*s.size.height+"%",p=s.opacity??1;t.style.cssText=`display:none;position:absolute;top:${o};bottom:${n};left:${r};right:${a};width:${d};height:${l};z-index:100;opacity:${p};`;break}default:t.style.cssText="display:none;position:absolute;top:0;left:0;right:0;bottom:0;z-index:100;background:#000;"}}restoreLayout(e){if(this.preparedLease&&!this.preparedLease.isActive())return;const t=e===s.DOUBLE||e===s.LSHAPE_AD||e===s.LSHAPE_CONTENT,i=this.deps.getPlayerContainer();if(!i)return;i.style.cssText="position:absolute;top:0;left:0;right:0;bottom:0;"+(t?"z-index:101;":"")+"transition:top 0.3s ease-in-out,left 0.3s ease-in-out,right 0.3s ease-in-out,bottom 0.3s ease-in-out,opacity 0.3s ease-in-out;",this.companionRemoveTimer&&clearTimeout(this.companionRemoveTimer);const o=this.deps.getCompanion();o&&(o.style.opacity="0"),this.companionRemoveTimer=setTimeout(()=>{const e=this.deps.getCompanion();e?.parentElement&&(e.parentElement.removeChild(e),this.deps.setCompanion(null)),this.companionRemoveTimer=null;const s=this.deps.getPlayerContainer();t&&s&&(s.style.zIndex="")},300)}renderCompanion(e,s){const i=e[0]?.companion;if(!i)return;const o=i.type===t.STATIC?this.deps.resolveUri(i.uri):null;if(!o)return;const n=document.createElement("img");n.className="dolby-companion",n.src=o,n.style.cssText=s;const r=this.deps.getStage();r&&(r.appendChild(n),this.deps.setCompanion(n),requestAnimationFrame(()=>{const e=this.deps.getCompanion();e&&(e.style.opacity="1")}))}clearOverlayImage(){const e=this.deps.getImageAssetTimer();e&&(clearTimeout(e),this.deps.setImageAssetTimer(null));const t=this.deps.getOverlayImage();t?.parentElement&&t.parentElement.removeChild(t),this.deps.setOverlayImage(null)}show(){const e=this.deps.getAdContainer();if(!e)return;this.adFadeTimer&&(clearTimeout(this.adFadeTimer),this.adFadeTimer=null);const t=this.deps.getCurrentBreak(),i=t?this.deps.getVariant(t):null;e.style.display="block",i?.format!==s.OVERLAY&&(this.deps.isChaining()?e.style.opacity="1":(e.style.opacity="0",requestAnimationFrame(()=>{const e=this.deps.getAdContainer();e&&(e.style.opacity="1")})))}hide(){const e=this.deps.getAdContainer();if(!e)return;const t=this.deps.getCurrentBreak(),i=t?this.deps.getVariant(t):null;i?.format!==s.OVERLAY?(e.style.opacity="0",this.adFadeTimer=setTimeout(()=>{const e=this.deps.getAdContainer();e&&(e.style.display="none"),this.adFadeTimer=null},300)):e.style.display="none"}restoreContent(e,t){if(this.releasePreparedPresentation())return!0;const s=this.deps.getPlayerContainer();if(!s)return!1;if(e)for(;s.firstChild;)this.deps.container.appendChild(s.firstChild);else this.deps.container.appendChild(s),s.style.cssText=t;return!1}releasePreparedPresentation(){return!!this.preparedLease&&(this.unsubscribeGeometry?.(),this.unsubscribeGeometry=null,this.preparedLease.release(),!0)}destroy(){this.unsubscribeGeometry?.(),this.unsubscribeGeometry=null;const e=this.deps.getContentVideo();e&&this.contentVideoGeometryHandler&&(e.removeEventListener("loadedmetadata",this.contentVideoGeometryHandler),e.removeEventListener("resize",this.contentVideoGeometryHandler)),this.contentVideoMutationObserver?.disconnect(),this.resizeObserver?.disconnect(),null!==this.resizePoll&&clearInterval(this.resizePoll),this.resizePoll=null,this.contentVideoMutationObserver=null,this.resizeObserver=null,this.contentVideoGeometryHandler=null,this.companionRemoveTimer&&clearTimeout(this.companionRemoveTimer),this.adFadeTimer&&clearTimeout(this.adFadeTimer)}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isVendorAsset as e}from"../../types/BreakManifest";import{appendQueryParameters as s,applyAssetParameterMacros as t,omitBreakScopedParameters as a}from"../assetParameterMacros";import{buildAssetParameterMacroTable as r}from"../assetParameterMacroTable";import{
|
|
1
|
+
import{isVendorAsset as e}from"../../types/BreakManifest";import{appendQueryParameters as s,applyAssetParameterMacros as t,omitBreakScopedParameters as a}from"../assetParameterMacros";import{buildAssetParameterMacroTable as r}from"../assetParameterMacroTable";import{objectEntries as i}from"../runtimeObject";import{resolveAssetParameters as o}from"../resolveAssetParameters";import{detectDeviceType as n}from"../detectDeviceType";import{resolveTargetedUri as m}from"../resolveTargetedUri";function d(e,s){if(e&&0===Object.keys(e).length&&(e=void 0),s&&0===Object.keys(s).length&&(s=void 0),e===s)return!0;if(!e||!s)return!1;const t=Object.keys(e);return t.length===Object.keys(s).length&&t.every(t=>e[t]===s[t])}export class AssetParameterResolver{constructor(e,s){this.state=e,this.deps=s}setSessionAssetParameters(e){this.state.sessionAssetParameters=e}setManifestAssetParameters(s){if(d(this.state.manifestAssetParameters,s))return;if(this.state.manifestAssetParameters=s,!this.deps.getGamStreamManager()?.isInitialized())return void this.deps.log("Manifest asset parameters stored before GAM initialization");const t=this.state.gamPodAsset;this.pushAssetParameters(t&&e(t)?t.assetParameters:void 0,t?.id),this.deps.diagnose("DA-ASSET-PARAMETERS-UPDATED","Manifest asset parameters changed; IMA targeting updated.",{source:"manifest",keys:Object.keys(s??{}).sort()})}updateAssetParameters(e){this.state.updatedAssetParameters=e,this.deps.getGamStreamManager()?.isInitialized()?this.pushAssetParameters(void 0):this.deps.log("updateAssetParameters: GAM not initialized, stored for VAST only")}updateAssetParameterMacros(e){const s={...this.state.sessionAssetParameterMacros};for(const[t,a]of i(e))void 0===a?delete s[t]:s[t]=a;this.state.sessionAssetParameterMacros=s,this.deps.diagnose("DA-ASSET-PARAMETERS-UPDATED","Asset parameter macros updated.",{source:"macros",keys:Object.keys(e).sort()}),this.deps.getGamStreamManager()?.isInitialized()?this.pushAssetParameters(void 0):this.deps.log("updateAssetParameterMacros: GAM not initialized, stored for VAST only")}setSessionAssetParameterMacros(e){this.state.sessionAssetParameterMacros={...e}}getSessionAssetParameterMacros(){return{...this.state.sessionAssetParameterMacros}}resolveAssetParameterMacros(e,s,i,o,n){const m="session"===i?a(e):e,d=t(m,r({customerMacros:this.state.sessionAssetParameterMacros,element:this.deps.container,breakDurationSec:"session"===i?void 0:s}),o);for(const{key:e,macro:s}of d.unresolved)this.deps.diagnose("DA-ASSET-MACRO-UNKNOWN",`Asset parameter '${e}' sent with literal macro '${s}': the macro has no value.`,{...n,key:e,macro:s});for(const{key:e,macro:s,pair:t}of d.omitted)this.deps.diagnose("DA-ASSET-PARAMETER-OMITTED",`Asset parameter '${e}' not sent: macro '${s}' is empty.`,{...n,key:e,macro:s,...void 0!==t?{pair:t}:{}});return d.params}resolveSessionAdTagParameters(){const e=o(this.state.sessionAssetParameters,this.state.updatedAssetParameters,this.state.manifestAssetParameters,void 0);return this.resolveAssetParameterMacros(e,void 0,"session","gam",{breakId:void 0,assetId:void 0})}buildVastTagUrl(e,t){const a=this.resolveUri(e.uri);if(!a)return null;const r=o(this.state.sessionAssetParameters,this.state.updatedAssetParameters,this.state.manifestAssetParameters,e.assetParameters),i=e.duration??this.deps.getEffectiveBreakDuration()??t.duration,n=this.resolveAssetParameterMacros(r,i,"break","vast",{breakId:t.id,assetId:e.id});return s(a,n)}pushAssetParameters(e,s){const t=this.deps.getGamStreamManager();if(!t?.isInitialized())return;const a=this.deps.getCurrentBreak(),r=o(this.state.sessionAssetParameters,this.state.updatedAssetParameters,this.state.manifestAssetParameters,e),i=this.resolveAssetParameterMacros(r,this.deps.getEffectiveBreakDuration()??a?.duration,"break","gam",{breakId:a?.id,assetId:s});null!==this.state.pushedAssetParameters&&d(this.state.pushedAssetParameters,i)||(this.state.pushedAssetParameters=i,t.replaceAdTagParameters(i??{}))}resolveUri(e){return void 0===this.state.detectedDeviceType&&(this.state.detectedDeviceType=n()),m(e,this.state.detectedDeviceType)}}
|