@dolby-optiview/ads-sdk-adapter-hlsjs 1.4.0 → 1.6.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.
@@ -1 +1 @@
1
- import e from"hls.js";import{decodeUtf8 as t,parseId3GeobFrames as s}from"@dolby-optiview/ads-sdk-core/id3";import{observeExternalPlayback as i,setExternalPlaybackAllowed as r}from"@dolby-optiview/ads-sdk-core/external-playback";import{HlsMediaError as n}from"./hlsErrorToMediaError";export class HlsJsAdapter{constructor(e,t){this.eventListeners=new Map,this.boundHandlers=new Map,this._programDateTime=null,this.deferredSeekTime=null,this.endedEmitted=!1,this.activeOperation=null,this.levelBeforePin=null,this.parsedCues=new Map,this.presentedPts=new Set,this.id3TrackListener=null,this.hls=e,this.video=t,this.externalPlayback=i(t,e=>this.emit("externalplaybackchange",e)),this.setupHlsListeners(),this.setupVideoListeners()}get currentTime(){return this.video.currentTime}get duration(){return this.video.duration}get isLive(){const e=this.hls?.latestLevelDetails;return"boolean"==typeof e?.live?e.live:null}get paused(){return this.video.paused}get playbackReady(){return this.video.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!this.video.seeking}get muted(){return this.video.muted}set muted(e){this.video.muted=e}get volume(){return this.video.volume}set volume(e){this.video.volume=e}get playbackRate(){return this.video.playbackRate}set playbackRate(e){this.video.playbackRate=e}get videoElement(){return this.video}get supportsParallelBuffering(){return e.isSupported()}get programDateTime(){return this._programDateTime}pause(){this.video.pause()}async play(){await this.video.play()}seek(e){this.video.seeking?this.deferredSeekTime=e:this.video.currentTime=e}get sourceUrl(){return this.hls.url??null}async load(t){this.endedEmitted=!1;const s=this.beginOperation();return new Promise((i,r)=>{const a=()=>{this.hls.off(e.Events.MANIFEST_PARSED,a),this.hls.off(e.Events.ERROR,o),this.endOperation(s),i()},o=(t,i)=>{i.fatal&&(this.hls.off(e.Events.MANIFEST_PARSED,a),this.hls.off(e.Events.ERROR,o),this.endOperation(s),r(new n("HLS load error",i)))};this.hls.on(e.Events.MANIFEST_PARSED,a),this.hls.on(e.Events.ERROR,o),this.hls.loadSource(t),this.hls.attachMedia(this.video)})}unload(){this.deferredSeekTime=null,this.activeOperation=null,this.hls.stopLoad(),this.hls.detachMedia()}recreateMediaPipeline(t){this.deferredSeekTime=null;const s=this.beginOperation();return new Promise((i,r)=>{const a=()=>{this.video.removeEventListener("loadedmetadata",o),this.hls.off(e.Events.FRAG_BUFFERED,h),this.hls.off(e.Events.ERROR,l),this.endOperation(s)},o=()=>{d()},h=()=>{d()},d=()=>{Math.abs(this.video.currentTime-t.startTime)>.5&&(this.video.currentTime=t.startTime),a(),i()},l=(e,t)=>{t.fatal&&(a(),r(new n("HLS pipeline recreate error",t)))};this.video.addEventListener("loadedmetadata",o),this.hls.on(e.Events.FRAG_BUFFERED,h),this.hls.on(e.Events.ERROR,l),this.hls.detachMedia(),this.hls.attachMedia(this.video);try{this.video.currentTime=t.startTime}catch{}this.hls.startLoad(t.startTime)})}async preload(t){if(e.isSupported())return new Promise(s=>{const i=new e({startFragPrefetch:!0,autoStartLoad:!0});let r=!1;const n=()=>{if(!r){r=!0,clearTimeout(h),i.off(e.Events.FRAG_LOADED,a),i.off(e.Events.ERROR,o);try{i.destroy()}catch{}s()}},a=()=>n(),o=(e,t)=>{t.fatal&&n()},h=setTimeout(n,8e3);i.on(e.Events.FRAG_LOADED,a),i.on(e.Events.ERROR,o),i.loadSource(t)})}get maxLiveSeekPosition(){const e=this.hls.latestLevelDetails;if(!e?.live)return null;const t=this.hls.liveSyncPosition;return"number"==typeof t&&Number.isFinite(t)?t:null}get targetDuration(){const e=this.hls.latestLevelDetails,t=e?.targetduration;return e?.live&&"number"==typeof t&&Number.isFinite(t)&&t>0?t:null}requestLiveStartOffset(e,t){const s=e;if(null===s||!Number.isFinite(s)||s<=0)return!1;if(this.hls.latestLevelDetails)return!1;const i=this.hls.config;return!(void 0===i.liveMaxLatencyDuration&&i.liveMaxLatencyDurationCount<=s)&&(delete i.liveSyncDuration,i.liveSyncDurationCount=s,this.hls.userConfig.liveSyncDurationCount=s,!0)}setVideoQuality(e){if(null===e){if(null===this.levelBeforePin)return!1;const e=this.levelBeforePin;try{return this.hls.nextLevel=e,this.hls.nextLevel!==e?!1:(this.levelBeforePin=null,!0)}catch{return!1}}const t=this.hls.levels;if(!t||t.length<2)return!1;let s=0;for(let e=1;e<t.length;e++)t[e].bitrate<t[s].bitrate&&(s=e);const i=t[s].bitrate;if("number"!=typeof i||!Number.isFinite(i)||i<=0)return!1;const r=null===this.levelBeforePin;let n;r&&(this.levelBeforePin=this.hls.manualLevel);try{this.hls.nextLevel=s,n=this.hls.nextLevel===s}catch{n=!1}return!!n||(r&&(this.levelBeforePin=null),!1)}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t)}off(e,t){const s=this.eventListeners.get(e);s&&s.delete(t)}get externalPlaybackState(){return this.externalPlayback?.state}setExternalPlaybackAllowed(e){r(this.video,e)}destroy(){this.externalPlayback?.dispose();for(const[e,t]of this.boundHandlers)this.video.removeEventListener(e,t);this.boundHandlers.clear(),this.eventListeners.clear(),this.deferredSeekTime=null,this.id3TrackListener&&(this.id3TrackListener.track.removeEventListener("cuechange",this.id3TrackListener.handler),this.id3TrackListener=null),this.parsedCues.clear(),this.presentedPts.clear()}beginOperation(){const e=Symbol("hls-operation");return this.activeOperation=e,e}endOperation(e){this.activeOperation===e&&(this.activeOperation=null)}setupHlsListeners(){this.hls.on(e.Events.ERROR,(e,t)=>{t.fatal&&null===this.activeOperation&&this.emit("error",new n("HLS playback error",t))}),this.hls.on(e.Events.MEDIA_ENDED,()=>{this.emitEndedOnce()}),this.hls.on(e.Events.FRAG_CHANGED,(e,t)=>{t.frag.programDateTime&&this.anchorProgramDateTime(t.frag.programDateTime,t.frag.start)}),this.hls.on(e.Events.LEVEL_LOADED,(e,t)=>{if(t.details.hasProgramDateTime&&t.details.fragments.length>0){const e=t.details.fragments[0];e.programDateTime&&this.anchorProgramDateTime(e.programDateTime,e.start)}}),this.hls.on(e.Events.FRAG_PARSING_METADATA,(e,i)=>{for(const e of i.samples??[]){const i=s(e.data);if(0===i.length){const t={type:"id3",startTime:e.pts,raw:e.data,phase:"parsed"};this.emit("timedmetadata",t);continue}const r=[];for(const s of i){const i={type:"id3",startTime:e.pts,description:s.description,mimeType:s.mimeType,messageData:t(s.data),raw:e.data,phase:"parsed"};r.push(i),this.emit("timedmetadata",i)}this.parsedCues.set(e.pts,r),this.pruneParsedCues()}this.attachId3CueEnterListener()})}attachId3CueEnterListener(){if(this.id3TrackListener)return;const e=this.video.textTracks;if(!e)return;let t;for(let s=0;s<e.length;s++){const i=e[s];if("metadata"===i.kind&&"id3"===i.label){t=i;break}}if(!t||"function"!=typeof t.addEventListener)return;"disabled"===t.mode&&(t.mode="hidden");const s=()=>{const e=t?.activeCues;if(e)for(let t=0;t<e.length;t++){const s=e[t].startTime;if(this.presentedPts.has(s))continue;const i=this.parsedCues.get(s);if(i){this.presentedPts.add(s);for(const e of i)this.emit("timedmetadata",{...e,phase:"presented"})}}};t.addEventListener("cuechange",s),this.id3TrackListener={track:t,handler:s}}pruneParsedCues(){const e=this.video.currentTime-120;for(const t of this.parsedCues.keys())t<e&&(this.parsedCues.delete(t),this.presentedPts.delete(t))}setupVideoListeners(){const e=()=>{this.updateProgramDateTime(),this.emit("timeupdate")},t=()=>{this.emitEndedOnce()},s=()=>{this.emit("error",this.video.error)},i=()=>{if(this.emit("seeked"),null!==this.deferredSeekTime){const e=this.deferredSeekTime;this.deferredSeekTime=null,this.seek(e)}},r=()=>{this.emit("volumechange")},n=()=>{this.emit("waiting")},a=()=>{this.endedEmitted=!1,this.emit("playing")},o=()=>{this.emit("pause")};this.video.addEventListener("timeupdate",e),this.video.addEventListener("ended",t),this.video.addEventListener("error",s),this.video.addEventListener("seeked",i),this.video.addEventListener("volumechange",r),this.video.addEventListener("waiting",n),this.video.addEventListener("playing",a),this.video.addEventListener("pause",o),this.boundHandlers.set("timeupdate",e),this.boundHandlers.set("ended",t),this.boundHandlers.set("error",s),this.boundHandlers.set("seeked",i),this.boundHandlers.set("volumechange",r),this.boundHandlers.set("waiting",n),this.boundHandlers.set("playing",a),this.boundHandlers.set("pause",o)}emitEndedOnce(){this.endedEmitted||(this.endedEmitted=!0,this.emit("ended"))}updateProgramDateTime(){const e=this.hls.levels,t=this.hls.currentLevel;if(t>=0&&e[t]?.details){const s=e[t].details;if(s?.hasProgramDateTime&&s.fragments.length>0){const e=s.fragments[0];e.programDateTime&&this.anchorProgramDateTime(e.programDateTime,e.start)}}}anchorProgramDateTime(e,t){this._programDateTime=new Date(e+1e3*(this.video.currentTime-t))}emit(e,t){const s=this.eventListeners.get(e);if(s)for(const e of s)try{e(t)}catch(e){console.error("[HlsJsAdapter] Event handler error:",e)}}}
1
+ import e from"hls.js";import{decodeUtf8 as t,parseId3GeobFrames as i}from"@dolby-optiview/ads-sdk-core/id3";import{observeExternalPlayback as s,setExternalPlaybackAllowed as r}from"@dolby-optiview/ads-sdk-core/external-playback";import{HlsMediaError as n}from"./hlsErrorToMediaError";export class HlsJsAdapter{constructor(e,t){this.eventListeners=new Map,this.boundHandlers=new Map,this._programDateTime=null,this.deferredSeekTime=null,this.endedEmitted=!1,this.activeOperation=null,this.levelBeforePin=null,this.parsedCues=new Map,this.presentedPts=new Set,this.id3TrackListener=null,this.hls=e,this.video=t,this.externalPlayback=s(t,e=>this.emit("externalplaybackchange",e)),this.setupHlsListeners(),this.setupVideoListeners()}get currentTime(){return this.video.currentTime}get duration(){return this.video.duration}get isLive(){const e=this.hls?.latestLevelDetails;return"boolean"==typeof e?.live?e.live:null}get paused(){return this.video.paused}get playbackReady(){return this.video.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!this.video.seeking}get muted(){return this.video.muted}set muted(e){this.video.muted=e}get volume(){return this.video.volume}set volume(e){this.video.volume=e}get playbackRate(){return this.video.playbackRate}set playbackRate(e){this.video.playbackRate=e}get videoElement(){return this.video}get supportsParallelBuffering(){return e.isSupported()}get programDateTime(){return this._programDateTime}pause(){this.video.pause()}async play(){await this.video.play()}seek(e){this.video.seeking?this.deferredSeekTime=e:this.video.currentTime=e}get sourceUrl(){return this.hls.url??null}async load(t){this.endedEmitted=!1;const i=this.beginOperation();return new Promise((s,r)=>{const a=()=>{this.hls.off(e.Events.MANIFEST_PARSED,a),this.hls.off(e.Events.ERROR,o),this.endOperation(i),s()},o=(t,s)=>{s.fatal&&(this.hls.off(e.Events.MANIFEST_PARSED,a),this.hls.off(e.Events.ERROR,o),this.endOperation(i),r(new n("HLS load error",s)))};this.hls.on(e.Events.MANIFEST_PARSED,a),this.hls.on(e.Events.ERROR,o),this.hls.loadSource(t),this.hls.attachMedia(this.video)})}unload(){this.deferredSeekTime=null,this.activeOperation=null,this.hls.stopLoad(),this.hls.detachMedia()}recreateMediaPipeline(t){this.deferredSeekTime=null;const i=this.beginOperation();return new Promise((s,r)=>{const a=()=>{this.video.removeEventListener("loadedmetadata",o),this.hls.off(e.Events.FRAG_BUFFERED,d),this.hls.off(e.Events.ERROR,l),this.endOperation(i)},o=()=>{h()},d=()=>{h()},h=()=>{Math.abs(this.video.currentTime-t.startTime)>.5&&(this.video.currentTime=t.startTime),a(),s()},l=(e,t)=>{t.fatal&&(a(),r(new n("HLS pipeline recreate error",t)))};this.video.addEventListener("loadedmetadata",o),this.hls.on(e.Events.FRAG_BUFFERED,d),this.hls.on(e.Events.ERROR,l),this.hls.detachMedia(),this.hls.attachMedia(this.video);try{this.video.currentTime=t.startTime}catch{}this.hls.startLoad(t.startTime)})}async preload(t){if(e.isSupported())return new Promise(i=>{const s=new e({startFragPrefetch:!0,autoStartLoad:!0});let r=!1;const n=()=>{if(!r){r=!0,clearTimeout(d),s.off(e.Events.FRAG_LOADED,a),s.off(e.Events.ERROR,o);try{s.destroy()}catch{}i()}},a=()=>n(),o=(e,t)=>{t.fatal&&n()},d=setTimeout(n,8e3);s.on(e.Events.FRAG_LOADED,a),s.on(e.Events.ERROR,o),s.loadSource(t)})}get maxLiveSeekPosition(){const e=this.hls.latestLevelDetails;if(!e?.live)return null;const t=this.hls.liveSyncPosition;return"number"==typeof t&&Number.isFinite(t)?t:null}get targetDuration(){const e=this.hls.latestLevelDetails,t=e?.targetduration;return e?.live&&"number"==typeof t&&Number.isFinite(t)&&t>0?t:null}requestLiveStartOffset(e,t){const i=e;if(null===i||!Number.isFinite(i)||i<=0)return!1;if(this.hls.latestLevelDetails)return!1;const s=this.hls.config;return!(void 0===s.liveMaxLatencyDuration&&s.liveMaxLatencyDurationCount<=i)&&(delete s.liveSyncDuration,s.liveSyncDurationCount=i,this.hls.userConfig.liveSyncDurationCount=i,!0)}setVideoQuality(e){if(null===e){if(null===this.levelBeforePin)return!1;const e=this.levelBeforePin;try{return this.hls.nextLevel=e,this.hls.nextLevel!==e?!1:(this.levelBeforePin=null,!0)}catch{return!1}}const t=this.hls.levels;if(!t||t.length<2)return!1;let i=0;for(let e=1;e<t.length;e++)t[e].bitrate<t[i].bitrate&&(i=e);const s=t[i].bitrate;if("number"!=typeof s||!Number.isFinite(s)||s<=0)return!1;const r=null===this.levelBeforePin;let n;r&&(this.levelBeforePin=this.hls.manualLevel);try{this.hls.nextLevel=i,n=this.hls.nextLevel===i}catch{n=!1}return!!n||(r&&(this.levelBeforePin=null),!1)}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t)}off(e,t){const i=this.eventListeners.get(e);i&&i.delete(t)}get externalPlaybackState(){return this.externalPlayback?.state}setExternalPlaybackAllowed(e){r(this.video,e)}destroy(){this.externalPlayback?.dispose();for(const[e,t]of this.boundHandlers)this.video.removeEventListener(e,t);this.boundHandlers.clear(),this.eventListeners.clear(),this.deferredSeekTime=null,this.id3TrackListener&&(this.id3TrackListener.track.removeEventListener("cuechange",this.id3TrackListener.handler),this.id3TrackListener=null),this.parsedCues.clear(),this.presentedPts.clear()}beginOperation(){const e=Symbol("hls-operation");return this.activeOperation=e,e}endOperation(e){this.activeOperation===e&&(this.activeOperation=null)}setupHlsListeners(){this.hls.on(e.Events.ERROR,(e,t)=>{t.fatal&&null===this.activeOperation&&this.emit("error",new n("HLS playback error",t))}),this.hls.on(e.Events.MEDIA_ENDED,()=>{this.emitEndedOnce()}),this.hls.on(e.Events.FRAG_CHANGED,(e,t)=>{t.frag.programDateTime&&this.anchorProgramDateTime(t.frag.programDateTime,t.frag.start)}),this.hls.on(e.Events.LEVEL_LOADED,(e,t)=>{if(t.details.hasProgramDateTime&&t.details.fragments.length>0){const e=t.details.fragments[0];e.programDateTime&&this.anchorProgramDateTime(e.programDateTime,e.start)}}),this.hls.on(e.Events.FRAG_PARSING_METADATA,(e,s)=>{for(const e of s.samples??[]){const s=i(e.data);if(0===s.length){const t={type:"id3",startTime:e.pts,raw:e.data,phase:"parsed"};this.emit("timedmetadata",t);continue}const r=[];for(const i of s){const s={type:"id3",startTime:e.pts,description:i.description,mimeType:i.mimeType,messageData:t(i.data),raw:e.data,phase:"parsed"};r.push(s),this.emit("timedmetadata",s)}this.parsedCues.set(e.pts,r),this.pruneParsedCues()}this.attachId3CueEnterListener()})}attachId3CueEnterListener(){if(this.id3TrackListener)return;const e=this.video.textTracks;if(!e)return;let t;for(let i=0;i<e.length;i++){const s=e[i];if("metadata"===s.kind&&"id3"===s.label){t=s;break}}if(!t||"function"!=typeof t.addEventListener)return;"disabled"===t.mode&&(t.mode="hidden");const i=()=>{const e=t?.activeCues;if(e)for(let t=0;t<e.length;t++){const i=e[t].startTime;if(this.presentedPts.has(i))continue;const s=this.parsedCues.get(i);if(s){this.presentedPts.add(i);for(const e of s)this.emit("timedmetadata",{...e,phase:"presented"})}}};t.addEventListener("cuechange",i),this.id3TrackListener={track:t,handler:i}}pruneParsedCues(){const e=this.video.currentTime-120;for(const t of this.parsedCues.keys())t<e&&(this.parsedCues.delete(t),this.presentedPts.delete(t))}setupVideoListeners(){const e=()=>{this.updateProgramDateTime(),this.emit("timeupdate")},t=()=>{this.emitEndedOnce()},i=()=>{this.emit("error",this.video.error)},s=()=>{if(this.emit("seeked"),null!==this.deferredSeekTime){const e=this.deferredSeekTime;this.deferredSeekTime=null,this.seek(e)}},r=()=>{this.emit("volumechange")},n=()=>{this.emit("waiting")},a=()=>{this.endedEmitted=!1,this.emit("playing")},o=()=>{this.emit("pause")},d=()=>{this.video.ended||(this.endedEmitted=!1)};this.video.addEventListener("timeupdate",e),this.video.addEventListener("ended",t),this.video.addEventListener("error",i),this.video.addEventListener("seeked",s),this.video.addEventListener("volumechange",r),this.video.addEventListener("waiting",n),this.video.addEventListener("playing",a),this.video.addEventListener("pause",o),this.video.addEventListener("seeking",d),this.boundHandlers.set("timeupdate",e),this.boundHandlers.set("ended",t),this.boundHandlers.set("error",i),this.boundHandlers.set("seeked",s),this.boundHandlers.set("volumechange",r),this.boundHandlers.set("waiting",n),this.boundHandlers.set("playing",a),this.boundHandlers.set("pause",o),this.boundHandlers.set("seeking",d)}emitEndedOnce(){this.endedEmitted||(this.endedEmitted=!0,this.emit("ended"))}updateProgramDateTime(){const e=this.hls.levels,t=this.hls.currentLevel;if(t>=0&&e[t]?.details){const i=e[t].details;if(i?.hasProgramDateTime&&i.fragments.length>0){const e=i.fragments[0];e.programDateTime&&this.anchorProgramDateTime(e.programDateTime,e.start)}}}anchorProgramDateTime(e,t){this._programDateTime=new Date(e+1e3*(this.video.currentTime-t))}emit(e,t){const i=this.eventListeners.get(e);if(i)for(const e of i)try{e(t)}catch(e){console.error("[HlsJsAdapter] Event handler error:",e)}}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dolby-optiview/ads-sdk-adapter-hlsjs",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "HLS.js adapter for OptiView Ads SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "sideEffects": false,
40
40
  "dependencies": {
41
- "@dolby-optiview/ads-sdk-core": "^1.4.0"
41
+ "@dolby-optiview/ads-sdk-core": "^1.6.0"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "hls.js": "^1.0.0"