UNPKG

npaw-plugin-adapters

Version:
311 lines (277 loc) 10 kB
import NativeAdsAdapter from "./ads/NativeAdsAdapter"; export default class BitmovinAdapter { adsAdapters = { nativeAdsAdapter: NativeAdsAdapter, }; getVersion() { return '7.0.11-bitmovin8-jsclass'; } getPlayhead() { let ret = this.player ? this.player.getCurrentTime() : null; if (this.getVideo().getAdsAdapter() && this.getVideo().getAdsAdapter().flags.isStarted) { ret = this.lastPlayhead || 0; } return ret; } getPlayrate() { return this.player ? this.player.getPlaybackSpeed() : null; } getStopParams() { let params = {}; if (this.getVideo().getPlayhead() > 0) { params = { playhead: this.getVideo().getPlayhead() }; } return params; } getDroppedFrames() { return this.player ? this.player.getDroppedVideoFrames() : null; } getDuration() { let ret = null; if (this.player) { this.lastDuration = this.player.getDuration() || this.lastDuration; ret = this.lastDuration; } return ret; } getBitrate() { let ret = null; if (this.player) { const videodata = this.player.getPlaybackVideoData(); const videoquality = this.player.getVideoQuality(); if (videoquality && videoquality.bitrate) { ret = videoquality.bitrate; } else if (videodata && videodata.bitrate) { ret = videodata.bitrate; } } return ret; } getRendition() { let ret = null; if (this.player) { const videodata = this.player.getPlaybackVideoData(); const videoquality = this.player.getVideoQuality(); if (videoquality && videoquality.bitrate) { ret = this.getNpawUtils().buildRenditionString(videoquality.width, videoquality.height, videoquality.bitrate); } else if (videodata && videodata.bitrate) { ret = this.getNpawUtils().buildRenditionString(videodata.width, videodata.height, videodata.bitrate); } } return ret; } detectQualityChange(e) { let ret; if (e.targetQuality && e.targetQuality.bitrate) { ret = this.getNpawUtils().buildRenditionString(e.targetQuality.width, e.targetQuality.height, e.targetQuality.bitrate); } if (ret && this.storeNewRendition) { this.storeNewRendition(ret); } } getTitle() { return this.player ? this.player.getSource().title : null; } getIsLive() { return this.player ? this.player.isLive() : null; } getResource() { let ret = null; if (this.player && this.player.getSource && this.player.getSource()) { try { if (this.player.getStreamType && this.player.getStreamType()) { if (this.player.getSource()[this.player.getStreamType()]) { return this.player.getSource()[this.player.getStreamType()]; } } } catch (e) { }; ret = this.player.getSource().progressive || this.player.getSource().hls; } try { if (this.player && this.player.getManifest && this.player.getManifest()) { if (this.player.getManifest().indexOf('MPD') > 0) { ret = this.player.getSource().dash; } else { ret = this.player.getSource().hls; } } } catch (err) { this.log.notice("Can't get manifest"); } return ret; } getPlayerVersion() { return this.player ? this.player.version : null; } getPlayerName() { return 'Bitmovin'; } /** * Verify that the Bitmovin player is fully initialized. * The player must exist and expose player.exports.PlayerEvent. * This method is used by higher layers to decide whether the adapter * can safely emit analytics events. */ checkExistsPlayer() { try { return !!(this.player && this.player.exports && this.player.exports.PlayerEvent); } catch (err) { return false; } } _checkAdsAdapter() { const adsAdapterInst = this.getVideo().getAdsAdapter(); if (!adsAdapterInst) { this.plugin.setAdsAdapter(this.getAdapterClass('nativeAdsAdapter'), this.getVideo().getVideoKey()); this.getVideo().getAdsAdapter().registerListeners(); } else if (adsAdapterInst && !adsAdapterInst.player) { adsAdapterInst.setPlayer(this.player); } } registerListeners() { // Guard against race condition: wait until player.exports is available if (!this.player || !this.player.exports || !this.player.exports.PlayerEvent) { this._registerRetryCount = (this._registerRetryCount || 0) + 1; if (this._registerRetryCount < 50) { // retry for ~5 seconds max setTimeout(() => this.registerListeners(), 100); } else if (this.log && typeof this.log.warn === 'function') { this.log.warn('BitmovinAdapter', 'Player not ready after maximum retries. Skipping listener registration.'); } return; } const events = this.player.exports.PlayerEvent; this.references = {}; this.references[events.Play] = this.playListener.bind(this); this.references[events.Paused] = this.pauseListener.bind(this); this.references[events.Playing] = this.playingListener.bind(this); this.references[events.Error] = this.errorListener.bind(this); this.references[events.Seek] = this.seekingListener.bind(this); this.references[events.TimeShift] = this.seekingListener.bind(this); this.references[events.TimeShifted] = this.seekedListener.bind(this); this.references[events.PlaybackFinished] = this.endedListener.bind(this); this.references[events.TimeChanged] = this.timeupdateListener.bind(this); this.references[events.SourceUnloaded] = this.endedListener.bind(this); this.references[events.Destroy] = this.destroyListener.bind(this); this.references[events.Ready] = this.readyListener.bind(this); this.references[events.AdBreakStarted] = this._checkAdsAdapter.bind(this); this.references[events.VideoPlaybackQualityChanged] = this.detectQualityChange.bind(this); this.references[events.StallStarted] = this.stallStartedListener.bind(this); this.references[events.StallEnded] = this.stallEndedListener.bind(this); for (let key in this.references) { this.player.on(key, this.references[key]); } this.plugin.setAdsAdapter(this.getAdapterClass('nativeAdsAdapter'), this.getVideo().getVideoKey()); this.getVideo().getAdsAdapter().registerListeners(); } unregisterListeners() { try { if (this.getVideo()) { this.getVideo().removeAdsAdapter(); } if (this.player && this.player.off && this.references) { for (let key in this.references) { this.player.off(key, this.references[key]) } delete this.references; } } catch (err) { } } readyListener(e) { this._checkAdsAdapter(); } playListener(e) { this.firePlayerLog('playListener', {}); this.lastPlayhead = 0; this.fireStart(); this.failedView = false; } timeupdateListener(e) { const previousLastPlayhead = this.lastPlayhead; if (!this.getVideo().getAdsAdapter() || !this.getVideo().getAdsAdapter().flags.isStarted) { this.lastPlayhead = this.player.getCurrentTime(); } if (this.getPlayhead() > 0.2 && (this.getIsLive() || this.getPlayhead() + 1 < this.getDuration())) { this.fireStart(); this.failedView = false; if (!this.flags.isJoined) { this.fireJoin(); } } if (!this.player.isPaused() && this.flags.isSeeking) { if (this.plugin && this.plugin.options && this.plugin.options.ignoreSeekInTimeUpdate) { const currentPosition = this.player.getCurrentTime(); if (this.seekStartPosition !== null) { const positionDifference = Math.abs(currentPosition - this.seekStartPosition); const playheadDifference = Math.abs(this.lastPlayhead - previousLastPlayhead); const threshold = 0.25; if (positionDifference > threshold || playheadDifference > threshold) { this.fireSeekEnd({}, 'timeupdateListener'); this.seekStartPosition = null; } else { // cancel seek to avoid automatic internal seeks to the same position // performed by the player when in PiP mode and screen is turned off this.cancelSeek(); } } } else { this.fireSeekEnd({}, 'timeupdateListener'); } } } pauseListener(e) { this.firePlayerLog('pauseListener', {}); if (e.issuer && e.issuer === 'ui-seek') { this.fireSeekBegin({}, false, 'pauseListener'); } else { this.firePause(); } } playingListener(e) { this.firePlayerLog('playingListener', {}); this.fireStart(); this.failedView = false; this.fireResume(); } errorListener(e) { this.firePlayerLog('errorListener', {}); if (this.failedView) return; if (!this.flags.isStarted) this.failedView = true; this.fireError(e.code, e.name); this.fireStop(this.getStopParams()); } seekingListener(e) { this.firePlayerLog('seekingListener', {}); this.seekStartPosition = e['position'] ?? this.player.getCurrentTime(); this.fireSeekBegin({}, false, 'seekingListener'); } seekedListener(e) { this.firePlayerLog('seekedListener', {}); this.fireSeekEnd({}, 'seekedListener'); } endedListener(e) { this.firePlayerLog('endedListener', {}); this.fireStop(this.getStopParams()); } stallStartedListener(e) { this.firePlayerLog('stallStartedListener', {}); this.fireBufferBegin({}, false, 'stallStartedListener'); } stallEndedListener(e) { this.firePlayerLog('stallEndedListener', {}); if (this.chronos && this.chronos.buffer && this.chronos.buffer.getDeltaTime(false) < 50) { this.cancelBuffer(); } else { this.fireBufferEnd({}, 'stallEndedListener'); } } destroyListener(e) { this.player = null; this.tag = null; this.fireStop(); this.getVideo().removeAdapter(); } getVideoBufferLength() { return this.player ? this.player.getVideoBufferLength() : null; } }