@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
|
-
export function isSharedElementUserAgent(e){return!!e&&/iPhone|iPod/i.test(e)}export function isSingleSurfaceWebDevice(e,
|
|
1
|
+
export function isSharedElementUserAgent(e){return!!e&&/iPhone|iPod/i.test(e)}export function isSingleSurfaceWebDevice(e,i=0){return!!e&&(!/\b(TV|SMART-TV|CrKey|AFT[A-Z]?)\b/i.test(e)&&(!(!/iPad|iPhone|iPod/i.test(e)&&!/Android/i.test(e))||/Macintosh/i.test(e)&&i>1))}export function detectMediaSourceCapabilities(){return{hasNativeMse:"undefined"!=typeof MediaSource,hasManagedMediaSource:"undefined"!=typeof window&&void 0!==window.ManagedMediaSource}}export function resolveInsertionMode(e,i=("undefined"!=typeof navigator?navigator.userAgent:""),t=detectMediaSourceCapabilities()){return"overlay"===e?"overlay":"shared-element"===e?isSharedElementUserAgent(i)?"shared-element":(console.warn('[OptiViewAds] adInsertion "shared-element" is only supported on iPhone/iPod (native HLS); falling back to "overlay" insertion on this platform.'),"overlay"):"adaptive"===e?"adaptive":isSharedElementUserAgent(i)?t.hasNativeMse?"overlay":t.hasManagedMediaSource?"adaptive":"shared-element":"overlay"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AUX_FETCH_TIMEOUT_MS=5e3;export async function fetchWithTimeout(t,r={},
|
|
1
|
+
import{xhrWithTimeout as e}from"./xhrWithTimeout";export const AUX_FETCH_TIMEOUT_MS=5e3;export async function fetchWithTimeout(t,r={},o=5e3,n=`no response within ${o}ms`){const i=r.signal??void 0;if(i?.aborted){const e=new Error("The operation was aborted.");throw e.name="AbortError",e}if("undefined"==typeof AbortController||"undefined"!=typeof Request&&!("signal"in Request.prototype))return e(t,r,o,n);const a=new AbortController;if("undefined"!=typeof Request)try{new Request("https://example.invalid/",{signal:a.signal})}catch{return e(t,r,o,n)}const s=setTimeout(()=>a.abort(),o),l=()=>a.abort();i?.addEventListener("abort",l);try{return await fetch(t,{...r,signal:a.signal})}catch(e){if(a.signal.aborted&&!i?.aborted)throw new Error(n,{cause:e});throw e}finally{clearTimeout(s),i?.removeEventListener("abort",l)}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const _=new Map([[100,"VAST_MALFORMED_RESPONSE"],[101,"VAST_SCHEMA_VALIDATION_ERROR"],[102,"VAST_UNSUPPORTED_VERSION"],[200,"VAST_TRAFFICKING_ERROR"],[201,"VAST_UNEXPECTED_LINEARITY"],[202,"VAST_UNEXPECTED_DURATION"],[300,"VAST_WRAPPER_ERROR"],[301,"VAST_LOAD_TIMEOUT"],[302,"VAST_TOO_MANY_REDIRECTS"],[303,"VAST_NO_ADS_AFTER_WRAPPER"],[400,"VIDEO_PLAY_ERROR"],[402,"VAST_MEDIA_LOAD_TIMEOUT"],[403,"VAST_LINEAR_ASSET_MISMATCH"],[405,"VAST_PROBLEM_DISPLAYING_MEDIA_FILE"],[900,"UNKNOWN_ERROR"],[901,"VPAID_ERROR"],[1005,"FAILED_TO_REQUEST_ADS"],[1007,"VAST_ASSET_NOT_FOUND"],[1009,"VAST_EMPTY_RESPONSE"],[1010,"UNKNOWN_AD_RESPONSE"],[1012,"ADS_REQUEST_NETWORK_ERROR"],[1013,"INVALID_AD_TAG"],[1022,"UNSUPPORTED_URL"]]);export function html5ImaErrorName(E){return _.get(E)}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* builds (never committed, like the version stamp):
|
|
5
5
|
*
|
|
6
6
|
* main branch → production (committed default, no stamp)
|
|
7
|
-
* any other branch → development (
|
|
7
|
+
* any other branch → development (staging ingest)
|
|
8
8
|
*
|
|
9
9
|
* The committed default is production on purpose: a build that somehow skips the
|
|
10
10
|
* stamp must degrade to "reports to production", never to "release artefact
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
import{objectEntries as e,objectFromEntries as s}from"./runtimeObject";function t(e){return"string"==typeof e&&""!==e.trim()?e:null}export function resolveGamVendorConfiguration(e){const s=e.vendorConfiguration,o={identity:null,unknownTypes:[],duplicateGam:!1,sgaiAssetParameters:void 0,ssai:null};if(!Array.isArray(s))return{...o,reason:"absent"};const r=[];let a=null,i=0;for(const e of s){if("object"!=typeof e||null===e)continue;const s=e,n=t(s.type);null!==n&&("gam"!==n?r.includes(n)||r.push(n):(i+=1,null===a&&(a=s)))}const u=i>1;if(null===a)return{...o,reason:"absent",unknownTypes:r,duplicateGam:u};const l=t(a.networkCode);if(null===l)return{...o,reason:"missing-network-code",unknownTypes:r,duplicateGam:u};const c=Array.isArray(a.ssai)?a.ssai[0]:void 0,y=("object"==typeof c&&null!==c?t(c.assetKey):null)??t(a.assetKey),f=y?{networkCode:l,assetKey:y,assetParameters:n("object"==typeof c&&null!==c?c.assetParameters:void 0)}:null,m=Array.isArray(a.sgai)?a.sgai[0]:void 0,d=("object"==typeof m&&null!==m?t(m.customAssetKey):null)??t(a.customAssetKey);if(null===d)return{...o,reason:"missing-custom-asset-key",unknownTypes:r,duplicateGam:u,ssai:f};return{identity:{networkCode:l,customAssetKey:d},reason:"ok",unknownTypes:r,duplicateGam:u,sgaiAssetParameters:n("object"==typeof m&&null!==m?m.assetParameters:void 0),ssai:f}}function n(t){if("object"!=typeof t||null===t||Array.isArray(t))return;const n=s(e(t).filter(e=>"string"==typeof e[1]));return Object.keys(n).length>0?n:void 0}export function gamPodIdentityMismatches(e,s){const t=[];return s.networkCode!==e.networkCode&&t.push({field:"networkCode",assetValue:s.networkCode,sessionValue:e.networkCode}),s.customAssetKey!==e.customAssetKey&&t.push({field:"customAssetKey",assetValue:s.customAssetKey,sessionValue:e.customAssetKey}),t}export function manifestHasGamAssets(e){for(const s of e.breaks??[]){const e=[...s.variants??[],...s.variant?[s.variant]:[]];for(const s of e)for(const e of s?.assets??[])if("gam"===e?.vendor)return!0}return!1}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveLiveStartPushback(position: number, seekableStart: number, seekableEnd: number, targetDuration: number, minimumDistanceTargetDurations?: number): number | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function resolveLiveStartPushback(e,t,n,r,u=5){const i=r*u;if(![e,t,n,r,u,i].every(Number.isFinite)||r<=0||u<=0||n<=t||n-e>=86400||n-e>=i)return null;const l=Math.max(t,n-i);return l<e?l:null}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AdBreakContentRecovery, AdInsertionMode, AdPreloadMode } from '../types/OptiViewAdsConfig';
|
|
2
|
+
import type { ResolvedContentRecovery } from './detectContentRecovery';
|
|
3
|
+
import type { ResolvedInsertionMode } from './detectInsertionMode';
|
|
4
|
+
import type { ResolvedPreloadMode } from './detectPreloadMode';
|
|
5
|
+
export type DiagnosticEmit = (code: string, message: string, context?: Record<string, unknown>) => void;
|
|
6
|
+
/**
|
|
7
|
+
* Emit the resolved-mode diagnostics so a report states them without inferring from timings:
|
|
8
|
+
* the preload mode, the post-break content recovery, and the shared-element downgrade.
|
|
9
|
+
*/
|
|
10
|
+
export declare function emitResolvedModeDiagnostics(configured: {
|
|
11
|
+
adPreload: AdPreloadMode;
|
|
12
|
+
adInsertion: AdInsertionMode;
|
|
13
|
+
adBreakContentRecovery: AdBreakContentRecovery;
|
|
14
|
+
}, resolved: {
|
|
15
|
+
preloadMode: ResolvedPreloadMode;
|
|
16
|
+
insertionMode: ResolvedInsertionMode;
|
|
17
|
+
contentRecovery: ResolvedContentRecovery;
|
|
18
|
+
}, emit: DiagnosticEmit): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function emitResolvedModeDiagnostics(e,o,r){r("DA-PRELOAD-MODE-RESOLVED",`Ad preload mode: ${o.preloadMode}`+(e.adPreload!==o.preloadMode?` (configured "${e.adPreload}")`:""),{configured:e.adPreload,resolved:o.preloadMode}),r("DA-CONTENT-RECOVERY-MODE-RESOLVED",`Post-break content recovery: ${o.contentRecovery}`+(e.adBreakContentRecovery!==o.contentRecovery?` (configured "${e.adBreakContentRecovery}")`:""),{configured:e.adBreakContentRecovery,resolved:o.contentRecovery}),"shared-element"===e.adInsertion&&"overlay"===o.insertionMode&&r("DA-SHARED-ELEMENT-UNSUPPORTED",'adInsertion "shared-element" is unsupported on this platform (non-iPhone/iPod); fell back to "overlay".',{configured:"shared-element",resolved:o.insertionMode})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function objectEntries(e){if("function"==typeof Object.entries)return Object.entries(e);const t=[];for(const r of Object.getOwnPropertyNames(e))Object.prototype.propertyIsEnumerable.call(e,r)&&t.push([r,e[r]]);return t}export function objectFromEntries(e){if("function"==typeof Object.fromEntries)return Object.fromEntries(e);const t={};for(const[r,n]of e)Object.defineProperty(t,r,{configurable:!0,enumerable:!0,writable:!0,value:n});return t}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../types/compatibility-modules";import{createRuntimePreparation as e,installMissingFunction as t}from"./webRuntime";function r(e,r,o,n){return{id:e,load:n,present:()=>"function"==typeof r[o],install:e=>t(r,o,e)}}export function webRuntimeFeatures(){const e=function(){if("undefined"!=typeof globalThis)return globalThis;const e="undefined"!=typeof self?self:window;return Object.defineProperty(e,"globalThis",{configurable:!0,writable:!0,value:e}),e}();return[r("Object.entries",Object,"entries",()=>import("core-js-pure/actual/object/entries.js").then(e=>e.default)),r("Object.values",Object,"values",()=>import("core-js-pure/actual/object/values.js").then(e=>e.default)),r("Object.fromEntries",Object,"fromEntries",()=>import("core-js-pure/actual/object/from-entries.js").then(e=>e.default)),r("Promise.allSettled",Promise,"allSettled",()=>import("core-js-pure/actual/promise/all-settled.js").then(e=>e.default)),r("Promise.finally",Promise.prototype,"finally",()=>import("core-js-pure/actual/promise/finally.js").then(e=>{const t=e.default;return function(e){return t(this,e)}})),r("URLSearchParams",e,"URLSearchParams",()=>import("core-js-pure/actual/url-search-params/index.js").then(e=>e.default)),r("URL",e,"URL",()=>import("core-js-pure/actual/url/index.js").then(e=>e.default)),{id:"AbortController",present:()=>"function"==typeof e.AbortController&&"function"==typeof e.AbortSignal,load:()=>"function"==typeof e.AbortController?Promise.resolve({AbortSignal:Object.getPrototypeOf((new e.AbortController).signal).constructor}):import("abort-controller/dist/abort-controller.js"),install:r=>{const o=r;t(e,"AbortController",o.AbortController),t(e,"AbortSignal",o.AbortSignal)}}]}let o;export function prepareWebRuntime(){const t=webRuntimeFeatures();return t.every(e=>e.present())?null:(o||(o=e(t)),o())}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface RuntimeFeature {
|
|
2
|
+
id: string;
|
|
3
|
+
present: () => boolean;
|
|
4
|
+
load: () => Promise<unknown>;
|
|
5
|
+
install: (implementation: unknown) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function createRuntimePreparation(features: readonly RuntimeFeature[]): () => Promise<void>;
|
|
8
|
+
export declare function installMissingFunction(target: object, key: string, implementation: unknown): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function createRuntimePreparation(e){let t;return()=>{if(!t){let i,r=!0;t=new Promise((t,n)=>{i=setTimeout(()=>{r=!1,n(new Error("SDK compatibility initialization timed out after 15000ms"))},15e3),Promise.resolve().then(()=>Promise.all(e.map(async e=>{if(e.present())return;const t=await e.load();if(r&&(e.present()||e.install(t),!e.present()))throw new Error(`SDK compatibility unavailable: ${e.id}`)}))).then(()=>t(),n)}).then(()=>{r=!1,clearTimeout(i)},e=>{throw r=!1,clearTimeout(i),t=void 0,e})}return t}}export function installMissingFunction(e,t,i){if("function"!=typeof e[t]){if("function"!=typeof i)throw new Error(`Invalid SDK compatibility module: ${t}`);Object.defineProperty(e,t,{configurable:!0,writable:!0,value:i})}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function xhrWithTimeout(url: string, init: RequestInit, timeoutMs: number, timeoutMessage: string): Promise<Response>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function xhrWithTimeout(e,r,t,o){return new Promise((n,s)=>{const a=new XMLHttpRequest,i=r.signal;let d,c=!1;const l=()=>{void 0!==d&&clearTimeout(d),i?.removeEventListener("abort",p),a.onload=a.onerror=a.onabort=null},u=e=>{c||(c=!0,l(),a.abort(),s(e))},p=()=>{const e=new Error("The operation was aborted.");e.name="AbortError",u(e)};try{if(i?.aborted)return void p();if("no-cors"===r.mode)throw new TypeError("Opaque requests require abortable fetch");if("omit"===r.credentials||"same-origin"===r.mode||r.integrity||r.redirect&&"follow"!==r.redirect)throw new TypeError("Request policy requires native abortable fetch");a.open(r.method??"GET",e,!0),a.responseType="arraybuffer",a.withCredentials="include"===r.credentials,new Headers(r.headers??{}).forEach((e,r)=>a.setRequestHeader(r,e)),a.onerror=()=>u(new TypeError("Network request failed")),a.onabort=p,a.onload=()=>{if(!c)try{const e=new Headers;for(const r of a.getAllResponseHeaders().trim().split(/[\r\n]+/)){const t=r.indexOf(":");t>0&&e.append(r.slice(0,t).trim(),r.slice(t+1).trim())}const t="HEAD"===r.method?.toUpperCase()||[204,205,304].includes(a.status),o=new Response(t?null:a.response,{status:a.status,statusText:a.statusText,headers:e});c=!0,l(),n(o)}catch(e){u(e instanceof Error?e:new Error(String(e)))}},i?.addEventListener("abort",p),d=setTimeout(()=>u(new Error(o)),t),a.send(r.body)}catch(e){u(e instanceof Error?e:new Error(String(e)))}})}
|
|
@@ -17,6 +17,9 @@ export declare class AdBreakStatusTracker {
|
|
|
17
17
|
activeBreakStartTimestamp: number | null;
|
|
18
18
|
activeBreakElapsedSec: number;
|
|
19
19
|
currentAdStartElapsedSec: number;
|
|
20
|
+
currentAdAssetId: string | null;
|
|
21
|
+
timelineAssetId: string | null;
|
|
22
|
+
timelineStartElapsedSec: number;
|
|
20
23
|
currentAdIndex: number | null;
|
|
21
24
|
currentAdTotal: number | null;
|
|
22
25
|
currentAdTime: number | null;
|
|
@@ -32,9 +35,9 @@ export declare class AdBreakStatusTracker {
|
|
|
32
35
|
setAdBreakStatusActive(breakInfo: Break, breakRemainingSec: number): void;
|
|
33
36
|
/** Mark the active break visible and playing: the first-frame signal for held pre-rolls, the first `playing` otherwise. */
|
|
34
37
|
setAdBreakVisible(breakInfo: Break): void;
|
|
35
|
-
onAdStarted(breakInfo: Break,
|
|
36
|
-
onAdEnded(breakInfo: Break): void;
|
|
37
|
-
onAdTimeUpdated(breakInfo: Break, currentTime: number, duration: number): void;
|
|
38
|
+
onAdStarted(breakInfo: Break, asset: Asset, index: number, total: number): void;
|
|
39
|
+
onAdEnded(breakInfo: Break, index: number, total: number): void;
|
|
40
|
+
onAdTimeUpdated(breakInfo: Break, asset: Asset, currentTime: number, duration: number): void;
|
|
38
41
|
onAdPlaybackWaiting(): void;
|
|
39
42
|
onAdPlaybackPlaying(): void;
|
|
40
43
|
private buildActiveAdBreakStatus;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export class AdBreakStatusTracker{constructor(t){this.deps=t,this.adBreakStatus={phase:"idle",break:null,ticking:!1},this.activeBreak=null,this.activeBreakRemainingAtStart=null,this.activeBreakStartTimestamp=null,this.activeBreakElapsedSec=0,this.currentAdStartElapsedSec=0,this.currentAdIndex=null,this.currentAdTotal=null,this.currentAdTime=null,this.currentAdDuration=null,this.activeBreakWaiting=!1,this.activeBreakPlaying=!1}getAdBreakStatus(){if("active"===this.adBreakStatus.phase)return{...this.adBreakStatus,breakRemainingSec:this.computeBreakRemainingSec()};if("upcoming"===this.adBreakStatus.phase&&this.activeBreak){const t=this.deps.secondsUntilBreak(this.activeBreak.id);return{...this.adBreakStatus,secondsUntilBreak:t}}return{...this.adBreakStatus}}onBreakWarning(t,e,i){this.activeBreak=t,this.emitAdBreakStatus({phase:"upcoming",break:t,format:this.deps.effectiveFormatOf(t),secondsUntilBreak:i,ticking:!1,warningSec:e})}setAdBreakStatusActive(t,e){this.activeBreak=t,this.activeBreakRemainingAtStart=e,this.activeBreakStartTimestamp=Date.now(),this.activeBreakElapsedSec=0,this.currentAdStartElapsedSec=0,this.currentAdIndex=null,this.currentAdTotal=null,this.currentAdTime=null,this.currentAdDuration=null,this.activeBreakWaiting=!1,this.activeBreakPlaying=!1,this.emitAdBreakStatus({phase:"active",break:t,format:this.deps.effectiveFormatOf(t),breakRemainingSec:this.activeBreakRemainingAtStart,ticking:!1})}setAdBreakVisible(t){this.activeBreakWaiting=!1,this.activeBreakPlaying=!0,this.emitAdBreakStatus({...this.buildActiveAdBreakStatus(t),ticking:!0})}onAdStarted(t,e,i,a){this.currentAdIndex=i,this.currentAdTotal=a,this.currentAdTime=null,this.currentAdDuration=null,this.currentAdStartElapsedSec=this.currentBreakElapsedSec(),this.activeBreakElapsedSec=this.currentAdStartElapsedSec,this.activeBreakWaiting=!1,this.activeBreakPlaying=!0,this.deps.breakTransitionTimer()?.settle("into-break","ad-to-ad","break-to-break"),this.emitAdBreakStatus({...this.buildActiveAdBreakStatus(t),adIndex:i,totalAds:a,adsRemaining:a-i,ticking:!0})}onAdEnded(t){null!==this.currentAdDuration&&Number.isFinite(this.currentAdDuration)?this.activeBreakElapsedSec=this.
|
|
1
|
+
export class AdBreakStatusTracker{constructor(t){this.deps=t,this.adBreakStatus={phase:"idle",break:null,ticking:!1},this.activeBreak=null,this.activeBreakRemainingAtStart=null,this.activeBreakStartTimestamp=null,this.activeBreakElapsedSec=0,this.currentAdStartElapsedSec=0,this.currentAdAssetId=null,this.timelineAssetId=null,this.timelineStartElapsedSec=0,this.currentAdIndex=null,this.currentAdTotal=null,this.currentAdTime=null,this.currentAdDuration=null,this.activeBreakWaiting=!1,this.activeBreakPlaying=!1}getAdBreakStatus(){if("active"===this.adBreakStatus.phase)return{...this.adBreakStatus,breakRemainingSec:this.computeBreakRemainingSec()};if("upcoming"===this.adBreakStatus.phase&&this.activeBreak){const t=this.deps.secondsUntilBreak(this.activeBreak.id);return{...this.adBreakStatus,secondsUntilBreak:t}}return{...this.adBreakStatus}}onBreakWarning(t,e,i){this.activeBreak=t,this.emitAdBreakStatus({phase:"upcoming",break:t,format:this.deps.effectiveFormatOf(t),secondsUntilBreak:i,ticking:!1,warningSec:e})}setAdBreakStatusActive(t,e){this.activeBreak=t,this.activeBreakRemainingAtStart=e,this.activeBreakStartTimestamp=Date.now(),this.activeBreakElapsedSec=0,this.currentAdStartElapsedSec=0,this.currentAdAssetId=null,this.timelineAssetId=null,this.timelineStartElapsedSec=0,this.currentAdIndex=null,this.currentAdTotal=null,this.currentAdTime=null,this.currentAdDuration=null,this.activeBreakWaiting=!1,this.activeBreakPlaying=!1,this.emitAdBreakStatus({phase:"active",break:t,format:this.deps.effectiveFormatOf(t),breakRemainingSec:this.activeBreakRemainingAtStart,ticking:!1})}setAdBreakVisible(t){this.activeBreakWaiting=!1,this.activeBreakPlaying=!0,this.emitAdBreakStatus({...this.buildActiveAdBreakStatus(t),ticking:!0})}onAdStarted(t,e,i,a){this.currentAdIndex=i,this.currentAdAssetId=e.id,this.currentAdTotal=a,this.currentAdTime=null,this.currentAdDuration=null,this.currentAdStartElapsedSec=this.currentBreakElapsedSec(),this.activeBreakElapsedSec=this.currentAdStartElapsedSec,this.activeBreakWaiting=!1,this.activeBreakPlaying=!0,this.deps.breakTransitionTimer()?.settle("into-break","ad-to-ad","break-to-break"),this.emitAdBreakStatus({...this.buildActiveAdBreakStatus(t),adIndex:i,totalAds:a,adsRemaining:a-i,ticking:!0})}onAdEnded(t,e,i){this.timelineAssetId===this.currentAdAssetId&&null!==this.currentAdDuration&&Number.isFinite(this.currentAdDuration)?this.activeBreakElapsedSec=this.timelineStartElapsedSec+this.currentAdDuration:null!==this.currentAdTime&&(this.activeBreakElapsedSec=this.timelineStartElapsedSec+this.currentAdTime),this.currentAdIndex=null,this.currentAdAssetId=null,this.currentAdTime=null,this.currentAdDuration=null,this.activeBreakPlaying=!1,this.emitAdBreakStatus({...this.buildActiveAdBreakStatus(t),adsRemaining:Math.max(0,i-e-1),breakRemainingSec:this.computeBreakRemainingSec(),ticking:!1})}onAdTimeUpdated(t,e,i,a){e.id!==this.timelineAssetId&&(this.timelineAssetId=e.id,this.timelineStartElapsedSec=null===this.currentAdIndex?this.currentBreakElapsedSec():this.currentAdStartElapsedSec),this.currentAdTime=i,this.currentAdDuration=a,this.activeBreakElapsedSec=this.timelineStartElapsedSec+i,this.activeBreakWaiting=!1,this.activeBreakPlaying=!0,this.emitAdBreakStatus({...this.buildActiveAdBreakStatus(t),breakRemainingSec:this.computeBreakRemainingSec(),ticking:!0})}onAdPlaybackWaiting(){this.activeBreakWaiting=!0,this.activeBreakPlaying=!1,this.activeBreak&&this.emitAdBreakStatus({...this.buildActiveAdBreakStatus(this.activeBreak),ticking:!1})}onAdPlaybackPlaying(){this.activeBreakWaiting=!1,this.activeBreakPlaying=!0,this.activeBreak&&this.emitAdBreakStatus({...this.buildActiveAdBreakStatus(this.activeBreak),ticking:!0})}buildActiveAdBreakStatus(t){return{phase:"active",break:t,format:this.deps.effectiveFormatOf(t),adIndex:this.currentAdIndex??void 0,totalAds:this.currentAdTotal??void 0,adsRemaining:null!==this.currentAdIndex&&null!==this.currentAdTotal?this.currentAdTotal-this.currentAdIndex:void 0,breakRemainingSec:this.computeBreakRemainingSec(),ticking:this.activeBreakPlaying&&!this.activeBreakWaiting}}computeBreakRemainingSec(){if(null!==this.activeBreakRemainingAtStart)return Math.max(0,this.activeBreakRemainingAtStart-this.currentBreakElapsedSec())}currentBreakElapsedSec(){let t=this.activeBreakElapsedSec;return 0===t&&null!==this.activeBreakStartTimestamp&&null===this.currentAdTime&&(t=(Date.now()-this.activeBreakStartTimestamp)/1e3),t}resetAdBreakStatus(){this.activeBreak=null,this.activeBreakRemainingAtStart=null,this.activeBreakStartTimestamp=null,this.activeBreakElapsedSec=0,this.currentAdStartElapsedSec=0,this.currentAdAssetId=null,this.timelineAssetId=null,this.timelineStartElapsedSec=0,this.currentAdIndex=null,this.currentAdTotal=null,this.currentAdTime=null,this.currentAdDuration=null,this.activeBreakWaiting=!1,this.activeBreakPlaying=!1,this.emitAdBreakStatus({phase:"idle",break:null,ticking:!1})}emitAdBreakStatus(t){this.statusesEqual(this.adBreakStatus,t)||(this.adBreakStatus=t,this.deps.emit("adbreakstatus",{type:"adbreakstatus",timestamp:Date.now(),status:t}))}statusesEqual(t,e){return t.phase===e.phase&&t.format===e.format&&t.secondsUntilBreak===e.secondsUntilBreak&&t.breakRemainingSec===e.breakRemainingSec&&t.adIndex===e.adIndex&&t.totalAds===e.totalAds&&t.adsRemaining===e.adsRemaining&&t.ticking===e.ticking&&t.warningSec===e.warningSec&&t.break?.id===e.break?.id}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BreakFormat as e}from"../types/BreakManifest";import{playbackErrorContext as t}from"../diagnostics/playbackErrorContext";export class BreakLifecycle{constructor(e,t){this.state=e,this.deps=t,this.breakBeginEmittedId=null,this.pendingAdBreakBegin=null}emitAdBreakBegin(e,t){this.breakBeginEmittedId!==e.id&&(this.breakBeginEmittedId=e.id,this.pendingAdBreakBegin=null,this.deps.emit("adbreakbegin",{type:"adbreakbegin",timestamp:Date.now(),break:e,format:this.deps.effectiveFormatOf(e),elapsedSec:t?.elapsedSec??0,remainingSec:t?.remainingSec??e.duration??0,...t?.tuneIn?{tuneIn:{elapsedSec:t.elapsedSec,remainingSec:t.remainingSec}}:{}}))}flushPendingAdBreakBegin(){this.pendingAdBreakBegin?.()}async onBreakStart(
|
|
1
|
+
import{BreakFormat as e}from"../types/BreakManifest";import{playbackErrorContext as t}from"../diagnostics/playbackErrorContext";import{adErrorCode as a}from"../types/AdError";import{VendorAdError as i}from"../types/VendorAdError";export class BreakLifecycle{constructor(e,t){this.state=e,this.deps=t,this.breakBeginEmittedId=null,this.pendingAdBreakBegin=null}emitAdBreakBegin(e,t){this.breakBeginEmittedId!==e.id&&(this.breakBeginEmittedId=e.id,this.pendingAdBreakBegin=null,this.deps.emit("adbreakbegin",{type:"adbreakbegin",timestamp:Date.now(),break:e,format:this.deps.effectiveFormatOf(e),elapsedSec:t?.elapsedSec??0,remainingSec:t?.remainingSec??e.duration??0,...t?.tuneIn?{tuneIn:{elapsedSec:t.elapsedSec,remainingSec:t.remainingSec}}:{}}))}flushPendingAdBreakBegin(){this.pendingAdBreakBegin?.()}async onBreakStart(d,r){if(this.state.snapbackSeekInFlight=!1,this.deps.adPlayerController.isAdPlaying())return this.deps.diagnose("DA-BREAK-SUPPRESSED-OVERLAP",`Break suppressed (ad already playing): ${d.id}`,{breakId:d.id}),this.deps.breakScheduler.completeBreak(d.id),void this.deps.onBreakSettled?.();this.deps.adPlayerController.diagnoseUnknownVariantFormats(d);const s=this.deps.adPlayerController.breakNothingToPlayReason(d);if(s)return this.deps.log("Break not begun (no playable variant):",d.id,s),this.deps.diagnose("DA-BREAK-NO-PLAYABLE-ASSET",`break ${d.id} has no playable variant (${s}); it will not begin.`,{breakId:d.id,reason:s}),this.deps.emit("aderror",{type:"aderror",timestamp:Date.now(),source:"ad",break:d,format:this.deps.effectiveFormatOf(d),error:new Error(`Break ${d.id} has no playable variant (${s})`)}),this.deps.breakScheduler.completeBreak(d.id),void this.deps.onBreakSettled?.();this.deps.log("Break starting:",d.id,r.tuneIn?"(tune-in)":""),this.deps.breakTransitionTimer?.mark("into-break",d.id),this.breakBeginEmittedId=null,this.pendingAdBreakBegin=null;const n=this.state.heldImmediatePreRollId===d.id,o=this.deps.effectiveFormatOf(d),k=o===e.SINGLE||o===e.LSHAPE_AD,p=n&&k;n&&(this.state.heldImmediatePreRollId=null),this.deps.adBreakStatusTracker.setAdBreakStatusActive(d,void 0!==r.remainingSec?r.remainingSec:d.duration),p||this.emitAdBreakBegin(d,r),this.deps.manifestService.setActive(!0),this.deps.breakScheduler.claimChain(d.id);const h={onAdStart:(e,t,a,i,d)=>{this.deps.adBreakStatusTracker.onAdStarted(e,t,a,i),this.deps.emit("adbegin",{type:"adbegin",timestamp:Date.now(),break:e,format:this.deps.effectiveFormatOf(e),asset:t,adIndex:a,totalAds:i,...d?.adId?{adId:d.adId}:{},...d?.creativeId?{creativeId:d.creativeId}:{},...void 0!==d?.podPosition?{podPosition:d.podPosition}:{}})},onAdEnd:(e,t,a,i,d)=>{this.deps.adBreakStatusTracker.onAdEnded(e,a,i),a+1<i&&this.deps.breakTransitionTimer?.mark("ad-to-ad",e.id),this.deps.emit("adend",{type:"adend",timestamp:Date.now(),break:e,format:this.deps.effectiveFormatOf(e),asset:t,adIndex:a,totalAds:i,...d?.adId?{adId:d.adId}:{},...d?.creativeId?{creativeId:d.creativeId}:{}})},onAdError:(e,d,r)=>{this.flushPendingAdBreakBegin(),this.deps.diagnose("DA-AD-PLAYBACK-ERROR",r.message,{breakId:e.id,assetId:d?.id,adErrorCode:a(r),...r instanceof i?{vendorCode:r.vendorCode}:{},...t(r)}),this.deps.emit("aderror",{type:"aderror",timestamp:Date.now(),source:"ad",break:e,format:this.deps.effectiveFormatOf(e),...d?{asset:d}:{},error:r})},onAdTimeUpdate:(e,t,a,i)=>{this.deps.adBreakStatusTracker.onAdTimeUpdated(e,t,a,i),this.deps.emit("adtimeupdate",{type:"adtimeupdate",timestamp:Date.now(),break:e,format:this.deps.effectiveFormatOf(e),asset:t,currentTime:a,duration:i})},onAdWaiting:(e,t)=>{this.deps.adBreakStatusTracker.onAdPlaybackWaiting(),this.deps.emit("waiting",{type:"waiting",timestamp:Date.now(),source:"ad",break:e,asset:t})},onAdPlaying:(e,t)=>{this.deps.adBreakStatusTracker.onAdPlaybackPlaying(),this.deps.emit("playing",{type:"playing",timestamp:Date.now(),source:"ad",break:e,asset:t})},onBreakEnd:e=>{this.onBreakEnd(e)},onBreakCut:e=>{this.deps.cmcdAdReporter.onBreakCut(e.id)},onBreakEndedWithoutContentPause:()=>{this.onBreakEndedWithoutContentPause()},onChainedBreakBegin:e=>{this.onChainedBreakBegin(e)},onChainedBreakSkipped:e=>{this.deps.log("Chained break skipped (no playable variant):",e.id),this.deps.breakScheduler.completeBreak(e.id)},onContentResumeSeek:(e,t)=>{this.deps.breakScheduler.notifyResumeSeek(e,t)},onContentReloading:e=>{this.deps.breakScheduler.setContentReloading(e)}};p&&(this.pendingAdBreakBegin=()=>this.emitAdBreakBegin(d,r),h.onBreakVisible=e=>{this.deps.adBreakStatusTracker.setAdBreakVisible(e),this.flushPendingAdBreakBegin()}),await this.deps.adPlayerController.playBreak(d,h,{effectiveDurationSec:r.remainingSec,firstFrameGate:p})}onChainedBreakBegin(e){this.deps.log("Chained break starting:",e.id),this.deps.breakTransitionTimer?.mark("break-to-break",e.id),this.deps.breakScheduler.activateChainedBreak(e.id),this.deps.manifestService.setActive(!0),this.deps.adBreakStatusTracker.setAdBreakStatusActive(e,e.duration),this.emitAdBreakBegin(e)}onBreakEnd(e){this.deps.log("Break ended:",e.id),this.deps.breakTransitionTimer?.mark("out-of-break",e.id),this.deps.breakScheduler.completeBreak(e.id),this.deps.manifestService.setActive(!1),this.deps.adBreakStatusTracker.resetAdBreakStatus(),this.flushPendingAdBreakBegin(),this.deps.emit("adbreakend",{type:"adbreakend",timestamp:Date.now(),break:e,format:this.deps.effectiveFormatOf(e)}),this.deps.onBreakSettled?.()}onBreakEndedWithoutContentPause(){this.deps.breakTransitionTimer?.settle("out-of-break"),this.deps.emit("playing",{type:"playing",timestamp:Date.now(),source:"content"})}onBreakAborted(e){if(this.deps.adPlayerController.isAdPlaying()){const t=this.deps.adBreakStatusTracker.currentBreakElapsedSec();this.deps.log(`Early return — ending break '${e.id}' at ${t.toFixed(2)}s`),this.deps.cmcdAdReporter.onBreakAborted(e.id),this.deps.adPlayerController.abortBreak(t)}else this.deps.breakScheduler.completeBreak(e.id),this.deps.onBreakSettled?.()}reportAbandonedBreak(e){const t=this.deps.adBreakStatusTracker.activeBreak;if(!t)return;const a=this.deps.adBreakStatusTracker.currentAdIndex;this.deps.diagnose("DA-BREAK-ABANDONED",`Session torn down (${e}) while break ${t.id} was still in flight`+(null!==a?"; an ad began and will never end.":"."),{breakId:t.id,cause:e,phase:this.deps.adBreakStatusTracker.adBreakStatus.phase,unbalancedAdBegin:null!==a,...null!==a?{adIndex:a}:{},...null!==this.deps.adBreakStatusTracker.currentAdTotal?{totalAds:this.deps.adBreakStatusTracker.currentAdTotal}:{}})}}
|
|
@@ -16,6 +16,7 @@ export interface SessionStarterDeps {
|
|
|
16
16
|
mode: OptiViewAdsMode;
|
|
17
17
|
hasExplicitMode: boolean;
|
|
18
18
|
continueContentDuringBreak: boolean;
|
|
19
|
+
startLivePushback: () => void;
|
|
19
20
|
manifestService: ManifestService | undefined;
|
|
20
21
|
breakScheduler: BreakScheduler | undefined;
|
|
21
22
|
adPlayerController: AdPlayerController | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getPreRollDelay as e}from"../types/BreakManifest";import{manifestHasGamAssets as s,resolveGamVendorConfiguration as t}from"../services/resolveGamVendorConfiguration";import{SsaiController as i}from"../services/SsaiController";import{resolveUrlOrigin as a}from"../services/urlOrigin";import{filterSsaiClientBreaks as r,resolveStitchedStreamVendor as n,SsaiUnavailableError as o}from"../services/resolveDeliveryMode";import{detectDeviceType as d}from"../services/detectDeviceType";import{decideDeliveryMode as l,detectChannelSwitch as h,gamPodIdentityChanged as c}from"../services/channelSwitch";const m=1e4;function p(e){return"stitcherUrl"in e}function S(e){return"string"==typeof e&&""!==e.trim()}export class SessionStarter{constructor(e,s){this.state=e,this.deps=s}async startSession(s){if("ssai"===this.deps.mode){if(!p(s)||!S(s.stitcherUrl))throw new Error('[OptiViewAds] mode "ssai" requires a stitcherUrl in startSession().')}else if(p(s)||!S(s.manifestUrl))throw new Error("[OptiViewAds] startSession requires a manifestUrl (the full break-manifest URL).");this.state.sessionActive&&(this.deps.log("Ending previous session before starting new one"),this.deps.endSessionInternal("session-restart"));const t=this.state.sessionGeneration;if(this.state.sessionActive=!0,this.deps.lensReporter.startSession(),p(s))return s.adInsertionType&&this.deps.diagnose("DA-INSERTION-TYPE-IGNORED-SSAI",`adInsertionType "${s.adInsertionType}" ignored in SSAI mode; the stitcher controls ad insertion.`,{adInsertionType:s.adInsertionType}),void await this.startSsaiSession(s,t);const i=s.manifestUrl;this.state.sessionConfig=s,this.state.manifestOrigin=a(i),this.deps.manifestService.setManifestUrl(i),this.deps.log("Session starting, manifest URL:",i);const r=Date.now(),n=e=>{this.deps.diagnose("DA-SESSION-STARTING",`Session start: ${e}`,{step:e,manifestUrl:i,elapsedMs:Date.now()-r})};n("begin");const o=s.assetParameters;let d;this.deps.adPlayerController.setSessionAssetParameters(o),this.deps.adPlayerController.setSessionAssetParameterMacros(s.assetParameterMacros),this.state.configSummary.gam&&(this.state.configSummary.gam={...this.state.configSummary.gam,hasAssetParameters:!!o}),n("manifest-fetch");try{d=await this.deps.manifestService.fetchManifest()}catch(e){if(this.isStaleStart(t))return;throw this.failSessionStart(e)}if(this.deps.cmcdAdReporter.onSessionStart(d),!this.isStaleStart(t))if(this.state.sessionManifest=d,"ssai"!==this.resolveSessionDeliveryMode(d))try{if(await this.startGamForManifest(d,o,n),this.isStaleStart(t))return;const a=s.adInsertionType;this.deps.adPlayerController.setBreakResumePolicy(a,d.timebase,this.deps.continueContentDuringBreak),this.deps.diagnose("DA-INSERTION-TYPE-RESOLVED",void 0===a?`Ad insertion type: unset — the manifest's resumeOffset drives the resume point (timebase: ${d.timebase})`:`Ad insertion type: ${a}, client-set (timebase: ${d.timebase})`,{adInsertionType:a??null,source:void 0===a?"unset":"client",timebase:d.timebase}),n("scheduling"),this.deps.breakScheduler.updateManifest(d),this.deps.pauseAdController.updateManifest(d),this.state.pauseAdTickInterval=setInterval(()=>this.deps.pauseAdController?.tick(),250);const r=(d.adStartDelay??0)>0?void 0:d.breaks.find(s=>0===e(s));r?(this.deps.adPlayerController.holdContentForPreRoll(r),this.state.heldImmediatePreRollId=r.id,this.state.heldPreRollArmed=!1,this.state.heldPreRollWaitStartedAt=Date.now(),this.contentIsReady()?this.armHeldImmediatePreRoll():this.state.heldPreRollArmInterval=setInterval(()=>{this.contentIsReady()?this.armHeldImmediatePreRoll():this.armHeldImmediatePreRollIfTimedOut()},250)):this.markPlaybackStartIfPlaying(),this.startBreakScheduler(),this.startManifestPolling(),this.deps.diagnose("DA-SESSION-STARTED",`Session active for manifest ${i}`,{manifestUrl:i}),this.deps.log("Session active")}catch(e){if(this.isStaleStart(t))return;throw this.failSessionStart(e)}else await this.startSteeredSsaiSession(d,s,n)}markPlaybackStartIfPlaying(){this.deps.player.paused||this.deps.breakScheduler.markPlaybackStart()}contentIsReady(){return!Number.isNaN(this.deps.player.duration)||!this.deps.player.paused}clearHeldImmediatePreRollArmInterval(){this.state.heldPreRollArmInterval&&(clearInterval(this.state.heldPreRollArmInterval),this.state.heldPreRollArmInterval=null)}armHeldImmediatePreRoll(){this.state.heldImmediatePreRollId&&!this.state.heldPreRollArmed&&(this.clearHeldImmediatePreRollArmInterval(),this.state.heldPreRollArmed=!0,this.deps.breakScheduler.markPlaybackStart())}armHeldImmediatePreRollIfTimedOut(){if(!this.state.heldImmediatePreRollId||this.state.heldPreRollArmed)return;const e=this.state.heldPreRollWaitStartedAt;if(null===e||Date.now()-e<m)return;const s=this.state.heldImmediatePreRollId;this.armHeldImmediatePreRoll(),this.deps.diagnose("DA-PREROLL-CONTENT-WAIT-TIMEOUT","Pending pre-roll began after waiting 10000ms for content readiness.",{breakId:s,waitMs:m})}cancelHeldImmediatePreRollOnContentError(){const e=this.state.heldImmediatePreRollId;return!(!e||this.state.heldPreRollArmed)&&(this.clearHeldImmediatePreRollArmInterval(),this.deps.breakScheduler?.completeBreak(e),this.deps.adPlayerController?.releaseContentHold(),this.state.heldImmediatePreRollId=null,this.state.heldPreRollArmed=!1,this.state.heldPreRollWaitStartedAt=null,this.deps.diagnose("DA-PREROLL-CANCELLED-CONTENT-ERROR","A pending pre-roll was cancelled because the content failed to load before it could begin.",{breakId:e}),!0)}clearHeldImmediatePreRollArm(){this.clearHeldImmediatePreRollArmInterval(),this.state.heldImmediatePreRollId=null,this.state.heldPreRollArmed=!1,this.state.heldPreRollWaitStartedAt=null}failSessionStart(e){const s=e instanceof Error?e:new Error(String(e)),t=this.deps.manifestService?.takeLastFailure();return this.deps.diagnose("DA-MANIFEST-FETCH-FAILED",s.message,t?{...t}:void 0),this.state.sessionActive=!1,this.deps.cmcdAdReporter.onSessionEnd(),this.deps.lensReporter.endSession(),s}resolveSessionDeliveryMode(e,s="manifest"){const t=this.state.sessionDeliveryMode,i=l(e,d(),this.deps.hasExplicitMode?this.deps.mode:null,s);return null!==i.unknownMode&&this.deps.diagnose("DA-DELIVERY-MODE-UNKNOWN",`Delivery rule ${i.ruleIndex} carries unrecognized mode "${i.unknownMode}"; using sgai.`,{unknownMode:i.unknownMode,ruleIndex:i.ruleIndex}),this.deps.hasExplicitMode&&i.manifestMode!==i.mode&&this.deps.diagnose("DA-DELIVERY-MODE-OVERRIDDEN",`Manifest delivery rules resolve "${i.manifestMode}" but the explicit config mode "${i.mode}" takes precedence.`,{manifestMode:i.manifestMode,configuredMode:i.mode}),this.state.sessionDeliveryMode=i.mode,this.deps.diagnose("DA-DELIVERY-MODE-RESOLVED",`Delivery mode: ${i.mode}`,{mode:i.mode,ruleIndex:i.ruleIndex,source:i.source,..."channel-switch"===s?{previousMode:t}:{}}),i.mode}async startSteeredSsaiSession(e,s,t){const i=n(e.vendorConfiguration);if(!i){const e="Manifest selected ssai delivery but no vendor configuration provides a stitched stream (no gam entry with an assetKey).";throw this.deps.diagnose("DA-SSAI-UNAVAILABLE",e),this.deps.manifestService.reset(),this.state.sessionActive=!1,new o(e)}try{t("ssai-live-stream"),this.state.steeredSsaiActive=!0,this.state.ssaiController=this.createSsaiController(i.networkCode),await this.state.ssaiController.startSteered(i,s.assetParameters,s.assetParameterMacros),t("scheduling");const a=r(e);this.deps.adPlayerController.setBreakResumePolicy(s.adInsertionType,e.timebase,!1),this.deps.breakScheduler.updateManifest(a),this.deps.pauseAdController.updateManifest(a),this.state.pauseAdTickInterval=setInterval(()=>this.deps.pauseAdController?.tick(),250),this.markPlaybackStartIfPlaying(),this.startBreakScheduler(),this.startManifestPolling(),this.deps.diagnose("DA-SESSION-STARTED",`SSAI session active (manifest-steered) for ${s.manifestUrl}`,{manifestUrl:s.manifestUrl}),this.deps.log("SSAI session active (manifest-steered)")}catch(e){const s=e instanceof Error?e:new Error(String(e));throw this.deps.diagnose("DA-SSAI-SESSION-FAILED",s.message),this.state.steeredSsaiActive=!1,this.deps.manifestService.reset(),this.state.sessionActive=!1,s}}createSsaiController(e){return new i(this.deps.player,{gam:this.state.steeredSsaiOptions?.streamActivityMonitorId?{streamActivityMonitorId:this.state.steeredSsaiOptions.streamActivityMonitorId}:{},ssai:{networkCode:e},maxBitrate:this.state.steeredSsaiOptions?.maxBitrate,autoplay:this.state.steeredSsaiOptions?.autoplay,debug:this.deps.debug},{emit:(e,s)=>this.deps.emit(e,s),diagnose:(e,s,t)=>this.deps.diagnose(e,s,t),log:(...e)=>this.deps.log(...e)})}startBreakScheduler(){this.deps.breakScheduler.start((e,s)=>{this.deps.breakLifecycle.onBreakStart(e,s)},e=>!this.deps.adPlayerController.isAdPlaying()&&(this.deps.adPlayerController.preload(e).catch(s=>{this.deps.diagnose("DA-PRELOAD-FAILED",s instanceof Error?s.message:String(s),{breakId:e.id})}),!0),(e,s,t)=>{this.deps.adBreakStatusTracker.onBreakWarning(e,s,t)},e=>{this.deps.breakLifecycle.onBreakAborted(e)})}startManifestPolling(){this.deps.manifestService.startPolling(e=>{if(!this.state.sessionActive)return;const s=this.deps.notedManifestBreakIds(e);this.deps.diagnose("DA-MANIFEST-POLLED","Manifest polled",{breaks:e.breaks.length,newBreakIds:s,pollingIntervalSeconds:this.deps.manifestService.currentPollingIntervalSeconds});const t=this.state.sessionManifest,i=t?h(t,e):null;if(this.state.pendingChannelSwitch||i&&this.deps.breakScheduler.getActiveBreak())return this.state.pendingChannelSwitch=e,void this.deps.log("Channel switch deferred until the active break ends");i?this.switchChannel(e,i):this.applyManifestUpdate(e)},e=>{this.state.sessionActive&&this.deps.diagnose("DA-MANIFEST-POLL-FAILED",e.message)})}applyPendingChannelSwitch(){if(!this.state.sessionActive||!this.state.pendingChannelSwitch)return;const e=this.state.pendingChannelSwitch;this.state.pendingChannelSwitch=null;const s=h(this.state.sessionManifest,e);s?this.switchChannel(e,s):this.applyManifestUpdate(e)}applyManifestUpdate(e){this.diagnoseIgnoredDeliveryModeChange(e);const s=t(e);this.state.steeredSsaiActive?this.state.ssaiController?.setManifestAssetParameters(s.ssai?.assetParameters):this.deps.adPlayerController.setManifestAssetParameters(s.sgaiAssetParameters);const i=this.state.steeredSsaiActive?r(e):e;this.deps.breakScheduler.updateManifest(i),this.deps.pauseAdController.updateManifest(i)}diagnoseIgnoredDeliveryModeChange(e){if(!this.state.sessionDeliveryMode)return;const s=l(e,d(),null,"manifest");s.manifestMode!==this.state.sessionDeliveryMode&&this.deps.diagnose("DA-DELIVERY-MODE-CHANGE-IGNORED",`Polled manifest resolves delivery mode "${s.manifestMode}" but "${this.state.sessionDeliveryMode}" is pinned for this session.`,{polledMode:s.manifestMode,pinnedMode:this.state.sessionDeliveryMode})}async switchChannel(e,s){if(this.state.channelSwitchInFlight)return;const t=this.state.sessionConfig,i=this.state.sessionManifest,a={previousChannelId:s.previousChannelId,channelId:s.channelId,reason:s.reason,manifestUrl:t.manifestUrl};this.deps.diagnose("DA-MANIFEST-CHANNEL-CHANGED",`Manifest channel changed (${s.reason}): ${s.previousChannelId??"none"} -> ${s.channelId??"none"}`,a),this.state.sessionManifest=e,this.state.channelSwitchInFlight=!0;const r=this.state.sessionGeneration,n=this.state.sessionDeliveryMode??"sgai";try{let s=this.resolveSessionDeliveryMode(e,"channel-switch");if(this.deps.cmcdAdReporter.onSessionEnd(),this.deps.cmcdAdReporter.onSessionStart(e),this.deps.lensReporter.endSession(),this.deps.lensReporter.startSession(),"ssai"===s&&"sgai"===n){const a=await this.switchToSteeredSsai(e,t);if(this.isStaleStart(r))return;a||(s="sgai",this.state.sessionDeliveryMode="sgai",await this.applySameModeChannelSwitch(i,e,t,r))}else"sgai"===s&&"ssai"===n?await this.switchToSgai(e,t,r):await this.applySameModeChannelSwitch(i,e,t,r);if(this.isStaleStart(r))return}finally{this.state.channelSwitchInFlight=!1}this.emitChannelChange({...a,previousDeliveryMode:n,deliveryMode:this.state.sessionDeliveryMode??n})}emitChannelChange(e){this.deps.emit("adchannelchange",{type:"adchannelchange",timestamp:Date.now(),...e})}async applySameModeChannelSwitch(e,s,i,a){const n=this.state.steeredSsaiActive,o=n?r(s):s;if(this.deps.breakScheduler.resetForChannelSwitch(o),this.deps.pauseAdController.updateManifest(o),this.deps.adPlayerController.setBreakResumePolicy(i.adInsertionType,s.timebase,this.deps.continueContentDuringBreak),!n&&c(e,s)){const e=this.deps.adPlayerController.updatedAssetParameters,t=this.deps.adPlayerController.sessionAssetParameterMacros;if(this.deps.adPlayerController.endGamSession(),this.deps.adPlayerController.setSessionAssetParameters(i.assetParameters),this.deps.adPlayerController.setSessionAssetParameterMacros(t),await this.startGamForManifest(s,i.assetParameters,e=>{this.deps.diagnose("DA-SESSION-STARTING",`Channel switch: ${e}`,{step:e,manifestUrl:i.manifestUrl})}),this.isStaleStart(a))return;e&&this.deps.adPlayerController.updateAssetParameters(e)}else if(n){const e=t(s);this.state.ssaiController?.setManifestAssetParameters(e.ssai?.assetParameters)}else{const e=t(s);this.deps.adPlayerController.setManifestAssetParameters(e.sgaiAssetParameters)}}async switchToSteeredSsai(e,s){const t=n(e.vendorConfiguration);if(!t)return this.deps.diagnose("DA-SSAI-UNAVAILABLE","Channel switch resolved ssai delivery but no vendor configuration provides a stitched stream; the session stays in sgai.",{manifestUrl:s.manifestUrl,previousMode:"sgai"}),!1;const i=this.deps.adPlayerController,a=i.updatedAssetParameters,o=i.sessionAssetParameterMacros;i.stopActiveBreak(),i.releaseContentHold(),i.endGamSession(),i.setSessionAssetParameters(s.assetParameters),i.setSessionAssetParameterMacros(o),a&&i.updateAssetParameters(a);const d=this.createSsaiController(t.networkCode);this.state.ssaiController=d,this.state.steeredSsaiActive=!0,this.deps.diagnose("DA-SESSION-STARTING","Channel switch: ssai-live-stream",{step:"ssai-live-stream",manifestUrl:s.manifestUrl});try{await d.startSteered(t,s.assetParameters,o),a&&d.updateAssetParameters(a);const n=r(e);return this.deps.breakScheduler.resetForChannelSwitch(n),this.deps.pauseAdController.updateManifest(n),i.setBreakResumePolicy(s.adInsertionType,e.timebase,!1),!0}catch(e){const s=e instanceof Error?e.message:String(e);return this.deps.diagnose("DA-SSAI-SESSION-FAILED",s),d.stop(),delete this.state.ssaiController,this.state.steeredSsaiActive=!1,!1}}async switchToSgai(e,s,t){const i=this.state.ssaiController?.sessionAssetParameterMacros;this.state.ssaiController?.stop(),delete this.state.ssaiController,this.state.steeredSsaiActive=!1,this.deps.breakScheduler.resetForChannelSwitch(e),this.deps.pauseAdController.updateManifest(e);const a=this.deps.adPlayerController;a.setBreakResumePolicy(s.adInsertionType,e.timebase,this.deps.continueContentDuringBreak);const r=a.updatedAssetParameters;a.endGamSession(),a.setSessionAssetParameters(s.assetParameters),a.setSessionAssetParameterMacros(i??s.assetParameterMacros),await this.startGamForManifest(e,s.assetParameters,e=>{this.deps.diagnose("DA-SESSION-STARTING",`Channel switch: ${e}`,{step:e,manifestUrl:s.manifestUrl})}),this.isStaleStart(t)||r&&a.updateAssetParameters(r)}async startGamForManifest(e,i,a){const r=t(e);if(this.deps.adPlayerController.setManifestAssetParameters(r.sgaiAssetParameters),r.unknownTypes.length>0&&this.deps.diagnose("DA-VENDOR-CONFIG-UNKNOWN-TYPE",`Ignored ${r.unknownTypes.length} vendorConfiguration `+(1===r.unknownTypes.length?"entry":"entries")+" with unrecognised type: "+`${r.unknownTypes.join(", ")}.`,{types:r.unknownTypes}),this.deps.adPlayerController.isGamEnabled())if(r.identity){this.deps.diagnose("DA-GAM-CONFIG-RESOLVED",`GAM session identity: network ${r.identity.networkCode}, custom asset ${r.identity.customAssetKey}`,{networkCode:r.identity.networkCode,customAssetKey:r.identity.customAssetKey,channelId:e.channelId,duplicateEntriesIgnored:r.duplicateGam});try{a("gam-init"),await this.deps.adPlayerController.startGamSession(r.identity,i),this.deps.log("GAM session started")}catch(e){this.deps.diagnose("DA-GAM-SESSION-FAILED",e instanceof Error?e.message:String(e))}}else s(e)&&this.deps.diagnose("DA-GAM-CONFIG-MISSING",'The break manifest carries GAM pod assets but no usable "gam" vendorConfiguration entry; those assets will be skipped.',{reason:r.reason});else s(e)&&this.deps.diagnose("DA-GAM-CONFIG-MISSING","The break manifest carries GAM pod assets but GAM is disabled for this session (gam.enabled === false); those assets will be skipped.",{reason:"gam-disabled"})}async startSsaiSession(e,s){try{if(this.state.stitcherOrigin=a(e.stitcherUrl),this.state.configSummary.gam&&(this.state.configSummary.gam={...this.state.configSummary.gam,hasAssetParameters:!!e.assetParameters}),await this.state.ssaiController.start(e),this.isStaleStart(s))return;this.deps.diagnose("DA-SESSION-STARTED",`SSAI session active for ${e.stitcherUrl}`,{stitcherUrl:e.stitcherUrl}),this.deps.log("SSAI session active")}catch(e){if(this.isStaleStart(s))return;const t=e instanceof Error?e:new Error(String(e));throw this.deps.diagnose("DA-SSAI-SESSION-FAILED",t.message),this.state.sessionActive=!1,this.deps.cmcdAdReporter.onSessionEnd(),this.deps.lensReporter.endSession(),t}}isStaleStart(e){return e!==this.state.sessionGeneration&&(this.deps.log("Session start aborted — the session ended or was replaced while starting"),!0)}}
|
|
1
|
+
import{getPreRollDelay as e}from"../types/BreakManifest";import{manifestHasGamAssets as s,resolveGamVendorConfiguration as t}from"../services/resolveGamVendorConfiguration";import{SsaiController as i}from"../services/SsaiController";import{resolveUrlOrigin as a}from"../services/urlOrigin";import{filterSsaiClientBreaks as r,resolveStitchedStreamVendor as n,SsaiUnavailableError as o}from"../services/resolveDeliveryMode";import{detectDeviceType as d}from"../services/detectDeviceType";import{decideDeliveryMode as l,detectChannelSwitch as h,gamPodIdentityChanged as c}from"../services/channelSwitch";import{prepareWebRuntime as m}from"../services/webCompatibility";const p=1e4;function S(e){return"stitcherUrl"in e}function u(e){return"string"==typeof e&&""!==e.trim()}export class SessionStarter{constructor(e,s){this.state=e,this.deps=s}async startSession(s){if("ssai"===this.deps.mode){if(!S(s)||!u(s.stitcherUrl))throw new Error('[OptiViewAds] mode "ssai" requires a stitcherUrl in startSession().')}else if(S(s)||!u(s.manifestUrl))throw new Error("[OptiViewAds] startSession requires a manifestUrl (the full break-manifest URL).");this.state.sessionActive&&(this.deps.log("Ending previous session before starting new one"),this.deps.endSessionInternal("session-restart"));const t=this.state.sessionGeneration;this.state.sessionActive=!0;try{const e=m();e&&await e}catch(e){if(this.isStaleStart(t))return;throw this.state.sessionActive=!1,e}if(this.isStaleStart(t))return;if(this.deps.lensReporter.startSession(),S(s))return s.adInsertionType&&this.deps.diagnose("DA-INSERTION-TYPE-IGNORED-SSAI",`adInsertionType "${s.adInsertionType}" ignored in SSAI mode; the stitcher controls ad insertion.`,{adInsertionType:s.adInsertionType}),void await this.startSsaiSession(s,t);const i=s.manifestUrl;this.state.sessionConfig=s,this.state.manifestOrigin=a(i),this.deps.manifestService.setManifestUrl(i),this.deps.log("Session starting, manifest URL:",i);const r=Date.now(),n=e=>{this.deps.diagnose("DA-SESSION-STARTING",`Session start: ${e}`,{step:e,manifestUrl:i,elapsedMs:Date.now()-r})};n("begin");const o=s.assetParameters;let d;this.deps.adPlayerController.setSessionAssetParameters(o),this.deps.adPlayerController.setSessionAssetParameterMacros(s.assetParameterMacros),this.state.configSummary.gam&&(this.state.configSummary.gam={...this.state.configSummary.gam,hasAssetParameters:!!o}),n("manifest-fetch");try{d=await this.deps.manifestService.fetchManifest()}catch(e){if(this.isStaleStart(t))return;throw this.failSessionStart(e)}if(this.deps.cmcdAdReporter.onSessionStart(d),!this.isStaleStart(t))if(this.state.sessionManifest=d,"ssai"!==this.resolveSessionDeliveryMode(d))try{if(await this.startGamForManifest(d,o,n),this.isStaleStart(t))return;const a=s.adInsertionType;this.deps.adPlayerController.setBreakResumePolicy(a,d.timebase,this.deps.continueContentDuringBreak),this.deps.diagnose("DA-INSERTION-TYPE-RESOLVED",void 0===a?`Ad insertion type: unset — the manifest's resumeOffset drives the resume point (timebase: ${d.timebase})`:`Ad insertion type: ${a}, client-set (timebase: ${d.timebase})`,{adInsertionType:a??null,source:void 0===a?"unset":"client",timebase:d.timebase}),n("scheduling"),this.deps.breakScheduler.updateManifest(d),this.deps.pauseAdController.updateManifest(d),this.state.pauseAdTickInterval=setInterval(()=>this.deps.pauseAdController?.tick(),250);const r=(d.adStartDelay??0)>0?void 0:d.breaks.find(s=>0===e(s));r?(this.deps.adPlayerController.holdContentForPreRoll(r),this.state.heldImmediatePreRollId=r.id,this.state.heldPreRollArmed=!1,this.state.heldPreRollWaitStartedAt=Date.now(),this.contentIsReady()?this.armHeldImmediatePreRoll():this.state.heldPreRollArmInterval=setInterval(()=>{this.contentIsReady()?this.armHeldImmediatePreRoll():this.armHeldImmediatePreRollIfTimedOut()},250)):this.markPlaybackStartIfPlaying(),this.deps.startLivePushback(),this.startBreakScheduler(),this.startManifestPolling(),this.deps.diagnose("DA-SESSION-STARTED",`Session active for manifest ${i}`,{manifestUrl:i}),this.deps.log("Session active")}catch(e){if(this.isStaleStart(t))return;throw this.failSessionStart(e)}else await this.startSteeredSsaiSession(d,s,n)}markPlaybackStartIfPlaying(){this.deps.player.paused||this.deps.breakScheduler.markPlaybackStart()}contentIsReady(){return!Number.isNaN(this.deps.player.duration)||!this.deps.player.paused}clearHeldImmediatePreRollArmInterval(){this.state.heldPreRollArmInterval&&(clearInterval(this.state.heldPreRollArmInterval),this.state.heldPreRollArmInterval=null)}armHeldImmediatePreRoll(){this.state.heldImmediatePreRollId&&!this.state.heldPreRollArmed&&(this.clearHeldImmediatePreRollArmInterval(),this.state.heldPreRollArmed=!0,this.deps.breakScheduler.markPlaybackStart())}armHeldImmediatePreRollIfTimedOut(){if(!this.state.heldImmediatePreRollId||this.state.heldPreRollArmed)return;const e=this.state.heldPreRollWaitStartedAt;if(null===e||Date.now()-e<p)return;const s=this.state.heldImmediatePreRollId;this.armHeldImmediatePreRoll(),this.deps.diagnose("DA-PREROLL-CONTENT-WAIT-TIMEOUT","Pending pre-roll began after waiting 10000ms for content readiness.",{breakId:s,waitMs:p})}cancelHeldImmediatePreRollOnContentError(){const e=this.state.heldImmediatePreRollId;return!(!e||this.state.heldPreRollArmed)&&(this.clearHeldImmediatePreRollArmInterval(),this.deps.breakScheduler?.completeBreak(e),this.deps.adPlayerController?.releaseContentHold(),this.state.heldImmediatePreRollId=null,this.state.heldPreRollArmed=!1,this.state.heldPreRollWaitStartedAt=null,this.deps.diagnose("DA-PREROLL-CANCELLED-CONTENT-ERROR","A pending pre-roll was cancelled because the content failed to load before it could begin.",{breakId:e}),!0)}clearHeldImmediatePreRollArm(){this.clearHeldImmediatePreRollArmInterval(),this.state.heldImmediatePreRollId=null,this.state.heldPreRollArmed=!1,this.state.heldPreRollWaitStartedAt=null}failSessionStart(e){const s=e instanceof Error?e:new Error(String(e)),t=this.deps.manifestService?.takeLastFailure();return this.deps.diagnose("DA-MANIFEST-FETCH-FAILED",s.message,t?{...t}:void 0),this.state.sessionActive=!1,this.deps.cmcdAdReporter.onSessionEnd(),this.deps.lensReporter.endSession(),s}resolveSessionDeliveryMode(e,s="manifest"){const t=this.state.sessionDeliveryMode,i=l(e,d(),this.deps.hasExplicitMode?this.deps.mode:null,s);return null!==i.unknownMode&&this.deps.diagnose("DA-DELIVERY-MODE-UNKNOWN",`Delivery rule ${i.ruleIndex} carries unrecognized mode "${i.unknownMode}"; using sgai.`,{unknownMode:i.unknownMode,ruleIndex:i.ruleIndex}),this.deps.hasExplicitMode&&i.manifestMode!==i.mode&&this.deps.diagnose("DA-DELIVERY-MODE-OVERRIDDEN",`Manifest delivery rules resolve "${i.manifestMode}" but the explicit config mode "${i.mode}" takes precedence.`,{manifestMode:i.manifestMode,configuredMode:i.mode}),this.state.sessionDeliveryMode=i.mode,this.deps.diagnose("DA-DELIVERY-MODE-RESOLVED",`Delivery mode: ${i.mode}`,{mode:i.mode,ruleIndex:i.ruleIndex,source:i.source,..."channel-switch"===s?{previousMode:t}:{}}),i.mode}async startSteeredSsaiSession(e,s,t){const i=n(e.vendorConfiguration);if(!i){const e="Manifest selected ssai delivery but no vendor configuration provides a stitched stream (no gam entry with an assetKey).";throw this.deps.diagnose("DA-SSAI-UNAVAILABLE",e),this.deps.manifestService.reset(),this.state.sessionActive=!1,new o(e)}try{t("ssai-live-stream"),this.state.steeredSsaiActive=!0,this.state.ssaiController=this.createSsaiController(i.networkCode),await this.state.ssaiController.startSteered(i,s.assetParameters,s.assetParameterMacros),t("scheduling");const a=r(e);this.deps.adPlayerController.setBreakResumePolicy(s.adInsertionType,e.timebase,!1),this.deps.breakScheduler.updateManifest(a),this.deps.pauseAdController.updateManifest(a),this.state.pauseAdTickInterval=setInterval(()=>this.deps.pauseAdController?.tick(),250),this.markPlaybackStartIfPlaying(),this.deps.startLivePushback(),this.startBreakScheduler(),this.startManifestPolling(),this.deps.diagnose("DA-SESSION-STARTED",`SSAI session active (manifest-steered) for ${s.manifestUrl}`,{manifestUrl:s.manifestUrl}),this.deps.log("SSAI session active (manifest-steered)")}catch(e){const s=e instanceof Error?e:new Error(String(e));throw this.deps.diagnose("DA-SSAI-SESSION-FAILED",s.message),this.state.steeredSsaiActive=!1,this.deps.manifestService.reset(),this.state.sessionActive=!1,s}}createSsaiController(e){return new i(this.deps.player,{gam:this.state.steeredSsaiOptions?.streamActivityMonitorId?{streamActivityMonitorId:this.state.steeredSsaiOptions.streamActivityMonitorId}:{},ssai:{networkCode:e},maxBitrate:this.state.steeredSsaiOptions?.maxBitrate,autoplay:this.state.steeredSsaiOptions?.autoplay,debug:this.deps.debug},{emit:(e,s)=>this.deps.emit(e,s),diagnose:(e,s,t)=>this.deps.diagnose(e,s,t),log:(...e)=>this.deps.log(...e)})}startBreakScheduler(){this.deps.breakScheduler.start((e,s)=>{this.deps.breakLifecycle.onBreakStart(e,s)},e=>!this.deps.adPlayerController.isAdPlaying()&&(this.deps.adPlayerController.preload(e).catch(s=>{this.deps.diagnose("DA-PRELOAD-FAILED",s instanceof Error?s.message:String(s),{breakId:e.id})}),!0),(e,s,t)=>{this.deps.adBreakStatusTracker.onBreakWarning(e,s,t)},e=>{this.deps.breakLifecycle.onBreakAborted(e)})}startManifestPolling(){this.deps.manifestService.startPolling(e=>{if(!this.state.sessionActive)return;const s=this.deps.notedManifestBreakIds(e);this.deps.diagnose("DA-MANIFEST-POLLED","Manifest polled",{breaks:e.breaks.length,newBreakIds:s,pollingIntervalSeconds:this.deps.manifestService.currentPollingIntervalSeconds});const t=this.state.sessionManifest,i=t?h(t,e):null;if(this.state.pendingChannelSwitch||i&&this.deps.breakScheduler.getActiveBreak())return this.state.pendingChannelSwitch=e,void this.deps.log("Channel switch deferred until the active break ends");i?this.switchChannel(e,i):this.applyManifestUpdate(e)},e=>{this.state.sessionActive&&this.deps.diagnose("DA-MANIFEST-POLL-FAILED",e.message)})}applyPendingChannelSwitch(){if(!this.state.sessionActive||!this.state.pendingChannelSwitch)return;const e=this.state.pendingChannelSwitch;this.state.pendingChannelSwitch=null;const s=h(this.state.sessionManifest,e);s?this.switchChannel(e,s):this.applyManifestUpdate(e)}applyManifestUpdate(e){this.diagnoseIgnoredDeliveryModeChange(e);const s=t(e);this.state.steeredSsaiActive?this.state.ssaiController?.setManifestAssetParameters(s.ssai?.assetParameters):this.deps.adPlayerController.setManifestAssetParameters(s.sgaiAssetParameters);const i=this.state.steeredSsaiActive?r(e):e;this.deps.breakScheduler.updateManifest(i),this.deps.pauseAdController.updateManifest(i)}diagnoseIgnoredDeliveryModeChange(e){if(!this.state.sessionDeliveryMode)return;const s=l(e,d(),null,"manifest");s.manifestMode!==this.state.sessionDeliveryMode&&this.deps.diagnose("DA-DELIVERY-MODE-CHANGE-IGNORED",`Polled manifest resolves delivery mode "${s.manifestMode}" but "${this.state.sessionDeliveryMode}" is pinned for this session.`,{polledMode:s.manifestMode,pinnedMode:this.state.sessionDeliveryMode})}async switchChannel(e,s){if(this.state.channelSwitchInFlight)return;const t=this.state.sessionConfig,i=this.state.sessionManifest,a={previousChannelId:s.previousChannelId,channelId:s.channelId,reason:s.reason,manifestUrl:t.manifestUrl};this.deps.diagnose("DA-MANIFEST-CHANNEL-CHANGED",`Manifest channel changed (${s.reason}): ${s.previousChannelId??"none"} -> ${s.channelId??"none"}`,a),this.state.sessionManifest=e,this.state.channelSwitchInFlight=!0;const r=this.state.sessionGeneration,n=this.state.sessionDeliveryMode??"sgai";try{let s=this.resolveSessionDeliveryMode(e,"channel-switch");if(this.deps.cmcdAdReporter.onSessionEnd(),this.deps.cmcdAdReporter.onSessionStart(e),this.deps.lensReporter.endSession(),this.deps.lensReporter.startSession(),"ssai"===s&&"sgai"===n){const a=await this.switchToSteeredSsai(e,t);if(this.isStaleStart(r))return;a||(s="sgai",this.state.sessionDeliveryMode="sgai",await this.applySameModeChannelSwitch(i,e,t,r))}else"sgai"===s&&"ssai"===n?await this.switchToSgai(e,t,r):await this.applySameModeChannelSwitch(i,e,t,r);if(this.isStaleStart(r))return}finally{this.state.channelSwitchInFlight=!1}this.deps.startLivePushback(),this.emitChannelChange({...a,previousDeliveryMode:n,deliveryMode:this.state.sessionDeliveryMode??n})}emitChannelChange(e){this.deps.emit("adchannelchange",{type:"adchannelchange",timestamp:Date.now(),...e})}async applySameModeChannelSwitch(e,s,i,a){const n=this.state.steeredSsaiActive,o=n?r(s):s;if(this.deps.breakScheduler.resetForChannelSwitch(o),this.deps.pauseAdController.updateManifest(o),this.deps.adPlayerController.setBreakResumePolicy(i.adInsertionType,s.timebase,this.deps.continueContentDuringBreak),!n&&c(e,s)){const e=this.deps.adPlayerController.updatedAssetParameters,t=this.deps.adPlayerController.sessionAssetParameterMacros;if(this.deps.adPlayerController.endGamSession(),this.deps.adPlayerController.setSessionAssetParameters(i.assetParameters),this.deps.adPlayerController.setSessionAssetParameterMacros(t),await this.startGamForManifest(s,i.assetParameters,e=>{this.deps.diagnose("DA-SESSION-STARTING",`Channel switch: ${e}`,{step:e,manifestUrl:i.manifestUrl})}),this.isStaleStart(a))return;e&&this.deps.adPlayerController.updateAssetParameters(e)}else if(n){const e=t(s);this.state.ssaiController?.setManifestAssetParameters(e.ssai?.assetParameters)}else{const e=t(s);this.deps.adPlayerController.setManifestAssetParameters(e.sgaiAssetParameters)}}async switchToSteeredSsai(e,s){const t=n(e.vendorConfiguration);if(!t)return this.deps.diagnose("DA-SSAI-UNAVAILABLE","Channel switch resolved ssai delivery but no vendor configuration provides a stitched stream; the session stays in sgai.",{manifestUrl:s.manifestUrl,previousMode:"sgai"}),!1;const i=this.deps.adPlayerController,a=i.updatedAssetParameters,o=i.sessionAssetParameterMacros;i.stopActiveBreak(),i.releaseContentHold(),i.endGamSession(),i.setSessionAssetParameters(s.assetParameters),i.setSessionAssetParameterMacros(o),a&&i.updateAssetParameters(a);const d=this.createSsaiController(t.networkCode);this.state.ssaiController=d,this.state.steeredSsaiActive=!0,this.deps.diagnose("DA-SESSION-STARTING","Channel switch: ssai-live-stream",{step:"ssai-live-stream",manifestUrl:s.manifestUrl});try{await d.startSteered(t,s.assetParameters,o),a&&d.updateAssetParameters(a);const n=r(e);return this.deps.breakScheduler.resetForChannelSwitch(n),this.deps.pauseAdController.updateManifest(n),i.setBreakResumePolicy(s.adInsertionType,e.timebase,!1),!0}catch(e){const s=e instanceof Error?e.message:String(e);return this.deps.diagnose("DA-SSAI-SESSION-FAILED",s),d.stop(),delete this.state.ssaiController,this.state.steeredSsaiActive=!1,!1}}async switchToSgai(e,s,t){const i=this.state.ssaiController?.sessionAssetParameterMacros;this.state.ssaiController?.stop(),delete this.state.ssaiController,this.state.steeredSsaiActive=!1,this.deps.breakScheduler.resetForChannelSwitch(e),this.deps.pauseAdController.updateManifest(e);const a=this.deps.adPlayerController;a.setBreakResumePolicy(s.adInsertionType,e.timebase,this.deps.continueContentDuringBreak);const r=a.updatedAssetParameters;a.endGamSession(),a.setSessionAssetParameters(s.assetParameters),a.setSessionAssetParameterMacros(i??s.assetParameterMacros),await this.startGamForManifest(e,s.assetParameters,e=>{this.deps.diagnose("DA-SESSION-STARTING",`Channel switch: ${e}`,{step:e,manifestUrl:s.manifestUrl})}),this.isStaleStart(t)||r&&a.updateAssetParameters(r)}async startGamForManifest(e,i,a){const r=t(e);if(this.deps.adPlayerController.setManifestAssetParameters(r.sgaiAssetParameters),r.unknownTypes.length>0&&this.deps.diagnose("DA-VENDOR-CONFIG-UNKNOWN-TYPE",`Ignored ${r.unknownTypes.length} vendorConfiguration `+(1===r.unknownTypes.length?"entry":"entries")+" with unrecognised type: "+`${r.unknownTypes.join(", ")}.`,{types:r.unknownTypes}),this.deps.adPlayerController.isGamEnabled())if(r.identity){this.deps.diagnose("DA-GAM-CONFIG-RESOLVED",`GAM session identity: network ${r.identity.networkCode}, custom asset ${r.identity.customAssetKey}`,{networkCode:r.identity.networkCode,customAssetKey:r.identity.customAssetKey,channelId:e.channelId,duplicateEntriesIgnored:r.duplicateGam});try{a("gam-init"),await this.deps.adPlayerController.startGamSession(r.identity,i),this.deps.log("GAM session started")}catch(e){this.deps.diagnose("DA-GAM-SESSION-FAILED",e instanceof Error?e.message:String(e))}}else s(e)&&this.deps.diagnose("DA-GAM-CONFIG-MISSING",'The break manifest carries GAM pod assets but no usable "gam" vendorConfiguration entry; those assets will be skipped.',{reason:r.reason});else s(e)&&this.deps.diagnose("DA-GAM-CONFIG-MISSING","The break manifest carries GAM pod assets but GAM is disabled for this session (gam.enabled === false); those assets will be skipped.",{reason:"gam-disabled"})}async startSsaiSession(e,s){try{if(this.state.stitcherOrigin=a(e.stitcherUrl),this.state.configSummary.gam&&(this.state.configSummary.gam={...this.state.configSummary.gam,hasAssetParameters:!!e.assetParameters}),await this.state.ssaiController.start(e),this.isStaleStart(s))return;this.deps.diagnose("DA-SESSION-STARTED",`SSAI session active for ${e.stitcherUrl}`,{stitcherUrl:e.stitcherUrl}),this.deps.startLivePushback(),this.deps.log("SSAI session active")}catch(e){if(this.isStaleStart(s))return;const t=e instanceof Error?e:new Error(String(e));throw this.deps.diagnose("DA-SSAI-SESSION-FAILED",t.message),this.state.sessionActive=!1,this.deps.cmcdAdReporter.onSessionEnd(),this.deps.lensReporter.endSession(),t}}isStaleStart(e){return e!==this.state.sessionGeneration&&(this.deps.log("Session start aborted — the session ended or was replaced while starting"),!0)}}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { KnownDiagnosticCode } from '../diagnostics/errorCodes';
|
|
2
|
+
/**
|
|
3
|
+
* An ad failure classified with its canonical `DA-*` code, which telemetry reports as CMCD
|
|
4
|
+
* `adec`. Failures that are not an `AdError` report the generic `DA-AD-PLAYBACK-ERROR`.
|
|
5
|
+
*/
|
|
6
|
+
export declare class AdError extends Error {
|
|
7
|
+
/** Canonical Ads SDK error code for this failure. */
|
|
8
|
+
readonly code: KnownDiagnosticCode;
|
|
9
|
+
constructor(message: string, code: KnownDiagnosticCode);
|
|
10
|
+
}
|
|
11
|
+
/** Canonical code of an ad failure; `DA-AD-PLAYBACK-ERROR` when it was not classified. */
|
|
12
|
+
export declare function adErrorCode(error: unknown): KnownDiagnosticCode;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export class AdError extends Error{constructor(r,o){super(r),this.name="AdError",this.code=o}}export function adErrorCode(r){return r instanceof AdError?r.code:"DA-AD-PLAYBACK-ERROR"}
|
package/dist/types/Events.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface AdBreakStatus {
|
|
|
23
23
|
adIndex?: number | undefined;
|
|
24
24
|
/** Total number of ads in the break, when known. */
|
|
25
25
|
totalAds?: number | undefined;
|
|
26
|
-
/** Number of ads remaining including the currently playing one. */
|
|
26
|
+
/** Number of ads remaining including the currently playing one; after an ad ends, the ads still to come. */
|
|
27
27
|
adsRemaining?: number | undefined;
|
|
28
28
|
/** Whether the countdown is advancing (ad rendered, playback progressing). `false` while buffering or before a held pre-roll's first frame. */
|
|
29
29
|
ticking: boolean;
|
|
@@ -75,6 +75,18 @@ export type ManifestRequestInterceptor = (request: ManifestRequest, context: Man
|
|
|
75
75
|
* content player can continue using the device's decoder until the break starts.
|
|
76
76
|
* @category Configuration */
|
|
77
77
|
export type AdPreloadMode = 'parallel' | 'single-decoder' | 'none' | 'auto';
|
|
78
|
+
/**
|
|
79
|
+
* How content is recovered when an ad break ends.
|
|
80
|
+
* - `recreate`: release the ad media, rebuild the content player's media pipeline at the resume
|
|
81
|
+
* position, then play. Needed on VIZIO SmartCast, where content cannot resume in the
|
|
82
|
+
* MediaSource an ad interrupted.
|
|
83
|
+
* - `none`: resume in place (seek + play).
|
|
84
|
+
* - `auto` (default): User-Agent based — VIZIO/SmartCast → `recreate`, else `none`.
|
|
85
|
+
*
|
|
86
|
+
* Web only: the Android, iOS and React Native bridges accept and ignore this option (their
|
|
87
|
+
* native players resume in place).
|
|
88
|
+
* @category Configuration */
|
|
89
|
+
export type AdBreakContentRecovery = 'recreate' | 'none' | 'auto';
|
|
78
90
|
/**
|
|
79
91
|
* Ad insertion strategy (compositing).
|
|
80
92
|
* - `overlay`: separate `<video>` over the content player; all break formats.
|
|
@@ -97,6 +109,18 @@ export type AdInsertionMode = 'overlay' | 'shared-element' | 'adaptive' | 'auto'
|
|
|
97
109
|
* is not consumed. Primarily for VOD (PTS timebase).
|
|
98
110
|
* @category SDK & Sessions */
|
|
99
111
|
export type AdInsertionType = 'replacement' | 'insertion';
|
|
112
|
+
/** Initial live-playback distance from the reported edge. @category Configuration */
|
|
113
|
+
export interface LiveStartPushbackConfig {
|
|
114
|
+
/**
|
|
115
|
+
* Apply once per session/channel. When omitted, it follows `ptsSource`: on for `'anvatoCue'`,
|
|
116
|
+
* off for `'mediaTime'`. An explicit value always wins.
|
|
117
|
+
*/
|
|
118
|
+
enabled?: boolean;
|
|
119
|
+
/** Minimum total distance in target durations, not an additional rewind. @default 5 */
|
|
120
|
+
minimumDistanceTargetDurations?: number;
|
|
121
|
+
/** Declared HLS target duration in seconds when the adapter cannot provide it. */
|
|
122
|
+
targetDurationSeconds?: number;
|
|
123
|
+
}
|
|
100
124
|
/**
|
|
101
125
|
* - `sgai` (default): the SDK polls the break manifest, schedules breaks and plays ads in its own overlay.
|
|
102
126
|
* - `ssai`: the content player plays a pre-stitched stream; the SDK only creates the IMA DAI
|
|
@@ -112,6 +136,8 @@ export declare const DEFAULT_MODE: OptiViewAdsMode;
|
|
|
112
136
|
* MediaSource before the break and wedges their only hardware decoder (black screen, no `adbreakbegin`).
|
|
113
137
|
*/
|
|
114
138
|
export declare const DEFAULT_AD_PRELOAD_MODE: AdPreloadMode;
|
|
139
|
+
/** `auto` rebuilds the content pipeline at break end on SmartCast panels and resumes in place elsewhere. */
|
|
140
|
+
export declare const DEFAULT_AD_BREAK_CONTENT_RECOVERY: AdBreakContentRecovery;
|
|
115
141
|
/** `auto` switches iPhone/iPod to shared-element insertion and leaves every other platform on overlay. */
|
|
116
142
|
export declare const DEFAULT_AD_INSERTION_MODE: AdInsertionMode;
|
|
117
143
|
/**
|
|
@@ -127,9 +153,9 @@ export type DoubleBoxAudio = 'ad' | 'content';
|
|
|
127
153
|
/** Default double-box audio focus: the ad, the side being monetised. */
|
|
128
154
|
export declare const DEFAULT_DOUBLE_BOX_AUDIO: DoubleBoxAudio;
|
|
129
155
|
/**
|
|
130
|
-
* Default hard-cut margin (seconds)
|
|
131
|
-
*
|
|
132
|
-
* break length finish cleanly.
|
|
156
|
+
* Default hard-cut margin (seconds), counted with the effective duration from first ad playback.
|
|
157
|
+
* Startup has its own watchdog; later stalls do not extend the playback cutoff.
|
|
158
|
+
* The margin lets an ad close to the break length finish cleanly.
|
|
133
159
|
*/
|
|
134
160
|
export declare const DEFAULT_AD_BREAK_CUT_SAFETY_MARGIN_SEC = 2;
|
|
135
161
|
/**
|
|
@@ -267,6 +293,12 @@ export interface OptiViewAdsConfig {
|
|
|
267
293
|
* @see AdPreloadMode
|
|
268
294
|
*/
|
|
269
295
|
adPreload?: AdPreloadMode;
|
|
296
|
+
/**
|
|
297
|
+
* Post-break content recovery strategy.
|
|
298
|
+
* @default 'auto'
|
|
299
|
+
* @see AdBreakContentRecovery
|
|
300
|
+
*/
|
|
301
|
+
adBreakContentRecovery?: AdBreakContentRecovery;
|
|
270
302
|
/**
|
|
271
303
|
* Ad insertion strategy. `auto` switches iPhone/iPod to shared-element insertion, all other platforms overlay.
|
|
272
304
|
* @default 'auto'
|
|
@@ -315,6 +347,11 @@ export interface OptiViewAdsConfig {
|
|
|
315
347
|
* @default false
|
|
316
348
|
*/
|
|
317
349
|
continueContentDuringBreak?: boolean;
|
|
350
|
+
/**
|
|
351
|
+
* Live startup adjustment, on by default with `ptsSource: 'anvatoCue'`; does not change later
|
|
352
|
+
* break-resume policy.
|
|
353
|
+
*/
|
|
354
|
+
liveStartPushback?: LiveStartPushbackConfig;
|
|
318
355
|
/** Hook on the parsed manifest before scheduling (initial fetch and every poll). See {@link ManifestResponseInterceptor}. */
|
|
319
356
|
interceptManifestResponse?: ManifestResponseInterceptor;
|
|
320
357
|
/**
|
|
@@ -323,8 +360,8 @@ export interface OptiViewAdsConfig {
|
|
|
323
360
|
*/
|
|
324
361
|
interceptManifestRequest?: ManifestRequestInterceptor;
|
|
325
362
|
/**
|
|
326
|
-
* Seconds added to
|
|
327
|
-
*
|
|
363
|
+
* Seconds added to the effective break duration, counted from first ad playback rather than
|
|
364
|
+
* loading. Later playing events do not reset it. `0` allows exactly that playback window.
|
|
328
365
|
* @default 2
|
|
329
366
|
*/
|
|
330
367
|
adBreakCutSafetyMarginSec?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const DEFAULT_MODE="sgai";export const DEFAULT_AD_PRELOAD_MODE="auto";export const DEFAULT_AD_INSERTION_MODE="auto";export const DEFAULT_DOUBLE_BOX_AUDIO="ad";export const DEFAULT_AD_BREAK_CUT_SAFETY_MARGIN_SEC=2;export const DEFAULT_CHAINING={enabled:!0,maxGapSeconds:2};export function resolveChaining(e){return{enabled:e?.enabled??DEFAULT_CHAINING.enabled,maxGapSeconds:e?.maxGapSeconds??DEFAULT_CHAINING.maxGapSeconds}}export const DEFAULT_TUNE_IN={enabled:!0,minBreakDurationSeconds:5};export function resolveTuneIn(e){return{enabled:e?.enabled??DEFAULT_TUNE_IN.enabled,minBreakDurationSeconds:e?.minBreakDurationSeconds??DEFAULT_TUNE_IN.minBreakDurationSeconds}}export const DEFAULT_PDT_GRACE_SECONDS=5;export function resolvePdtGraceSeconds(e){return Math.max(0,e??5)}export const DEFAULT_BREAK_WARNINGS={seconds:[]};export function resolveBreakWarnings(e){const n=e?.seconds??[];return{seconds:Array.from(new Set(n.map(e=>Math.round(e)).filter(e=>Number.isFinite(e)&&e>0))).sort((e,n)=>e-n)}}
|
|
1
|
+
export const DEFAULT_MODE="sgai";export const DEFAULT_AD_PRELOAD_MODE="auto";export const DEFAULT_AD_BREAK_CONTENT_RECOVERY="auto";export const DEFAULT_AD_INSERTION_MODE="auto";export const DEFAULT_DOUBLE_BOX_AUDIO="ad";export const DEFAULT_AD_BREAK_CUT_SAFETY_MARGIN_SEC=2;export const DEFAULT_CHAINING={enabled:!0,maxGapSeconds:2};export function resolveChaining(e){return{enabled:e?.enabled??DEFAULT_CHAINING.enabled,maxGapSeconds:e?.maxGapSeconds??DEFAULT_CHAINING.maxGapSeconds}}export const DEFAULT_TUNE_IN={enabled:!0,minBreakDurationSeconds:5};export function resolveTuneIn(e){return{enabled:e?.enabled??DEFAULT_TUNE_IN.enabled,minBreakDurationSeconds:e?.minBreakDurationSeconds??DEFAULT_TUNE_IN.minBreakDurationSeconds}}export const DEFAULT_PDT_GRACE_SECONDS=5;export function resolvePdtGraceSeconds(e){return Math.max(0,e??5)}export const DEFAULT_BREAK_WARNINGS={seconds:[]};export function resolveBreakWarnings(e){const n=e?.seconds??[];return{seconds:Array.from(new Set(n.map(e=>Math.round(e)).filter(e=>Number.isFinite(e)&&e>0))).sort((e,n)=>e-n)}}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import type { KnownDiagnosticCode } from '../diagnostics/errorCodes';
|
|
2
|
+
import { AdError } from './AdError';
|
|
1
3
|
/**
|
|
2
4
|
* An ad playback error that carries the ad vendor's own error code (e.g. the
|
|
3
5
|
* numeric IMA/VAST `AdError` code), so telemetry can report it (`adevc`)
|
|
4
|
-
* alongside the SDK's
|
|
5
|
-
* this type when the vendor supplies a code
|
|
6
|
-
* `Error`s.
|
|
6
|
+
* alongside the SDK's canonical code (`adec`). Vendor integrations wrap their
|
|
7
|
+
* errors in this type when the vendor supplies a code.
|
|
7
8
|
*/
|
|
8
|
-
export declare class VendorAdError extends
|
|
9
|
+
export declare class VendorAdError extends AdError {
|
|
9
10
|
/** The vendor's error code, stringified (e.g. IMA's numeric AdError code). */
|
|
10
11
|
readonly vendorCode: string;
|
|
11
|
-
constructor(message: string, vendorCode: string);
|
|
12
|
+
constructor(message: string, vendorCode: string, code?: KnownDiagnosticCode);
|
|
12
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export class VendorAdError extends
|
|
1
|
+
import{AdError as r}from"./AdError";export class VendorAdError extends r{constructor(r,o,e="DA-AD-PLAYBACK-ERROR"){super(r,e),this.name="VendorAdError",this.vendorCode=o}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { Lens } from './lens';
|
|
2
2
|
export { LensEventType, LensToken } from './types';
|
|
3
|
-
export type { LensAdPayload, LensConsent, LensBackend, LensConfigureOptions, LensDestination, LensDestinationFilter, LensEvent, LensEventKeys, LensHandle, LensJoinOptions, LensPayload, LensSession, LensStartSessionOptions, } from './types';
|
|
3
|
+
export type { LensAdPayload, LensBatch, LensConsent, LensBackend, LensConfigureOptions, LensDestination, LensDestinationFilter, LensEvent, LensEventKeys, LensHandle, LensJoinOptions, LensPayload, LensSession, LensSourceChange, LensStartSessionOptions, } from './types';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{L as Lens,a as LensEventType,b as LensToken}from"./lens-core-
|
|
1
|
+
export{L as Lens,a as LensEventType,b as LensToken}from"./lens-core-uGZfZpQy.js";
|