UNPKG

videojs-vast-vpaid

Version:
220 lines (173 loc) 6.66 kB
const VASTError = require('../vast/VASTError'); const utilities = require('../../utils/utilityFunctions'); function VPAIDAdUnitWrapper (vpaidAdUnit, opts) { if (!(this instanceof VPAIDAdUnitWrapper)) { return new VPAIDAdUnitWrapper(vpaidAdUnit, opts); } sanityCheck(vpaidAdUnit, opts); this.options = utilities.extend({}, opts); this._adUnit = vpaidAdUnit; /** * Local Functions ***/ function sanityCheck (adUnit, opts) { if (!adUnit || !VPAIDAdUnitWrapper.checkVPAIDInterface(adUnit)) { throw new VASTError('on VPAIDAdUnitWrapper, the passed VPAID adUnit does not fully implement the VPAID interface'); } if (!utilities.isObject(opts)) { throw new VASTError('on VPAIDAdUnitWrapper, expected options hash but got \'' + opts + '\''); } if (!('responseTimeout' in opts) || !utilities.isNumber(opts.responseTimeout)) { throw new VASTError('on VPAIDAdUnitWrapper, expected responseTimeout in options'); } } } VPAIDAdUnitWrapper.checkVPAIDInterface = function checkVPAIDInterface (VPAIDAdUnit) { // NOTE: skipAd is not part of the method list because it only appears in VPAID 2.0 and we support VPAID 1.0 const VPAIDInterfaceMethods = [ 'handshakeVersion', 'initAd', 'startAd', 'stopAd', 'resizeAd', 'pauseAd', 'expandAd', 'collapseAd' ]; for (let i = 0, len = VPAIDInterfaceMethods.length; i < len; i++) { if (!VPAIDAdUnit || !utilities.isFunction(VPAIDAdUnit[VPAIDInterfaceMethods[i]])) { return false; } } return canSubscribeToEvents(VPAIDAdUnit) && canUnsubscribeFromEvents(VPAIDAdUnit); /** * Local Functions ***/ function canSubscribeToEvents (adUnit) { return utilities.isFunction(adUnit.subscribe) || utilities.isFunction(adUnit.addEventListener) || utilities.isFunction(adUnit.on); } function canUnsubscribeFromEvents (adUnit) { return utilities.isFunction(adUnit.unsubscribe) || utilities.isFunction(adUnit.removeEventListener) || utilities.isFunction(adUnit.off); } }; VPAIDAdUnitWrapper.prototype.adUnitAsyncCall = function (...args) { const method = args.shift(); let cb = args.pop(); let timeoutId; sanityCheck(method, cb, this._adUnit); args.push(wrapCallback()); this._adUnit[method](...args); timeoutId = setTimeout(() => { timeoutId = null; cb(new VASTError('on VPAIDAdUnitWrapper, timeout while waiting for a response on call \'' + method + '\'')); cb = utilities.noop; }, this.options.responseTimeout); /** * Local functions ***/ function sanityCheck (method, cb, adUnit) { if (!utilities.isString(method) || !utilities.isFunction(adUnit[method])) { throw new VASTError('on VPAIDAdUnitWrapper.adUnitAsyncCall, invalid method name'); } if (!utilities.isFunction(cb)) { throw new VASTError('on VPAIDAdUnitWrapper.adUnitAsyncCall, missing callback'); } } function wrapCallback () { return function () { if (timeoutId) { clearTimeout(timeoutId); } cb.apply(this, arguments); }; } }; VPAIDAdUnitWrapper.prototype.on = function (evtName, handler) { const addEventListener = this._adUnit.addEventListener || this._adUnit.subscribe || this._adUnit.on; addEventListener.call(this._adUnit, evtName, handler); }; VPAIDAdUnitWrapper.prototype.off = function (evtName, handler) { const removeEventListener = this._adUnit.removeEventListener || this._adUnit.unsubscribe || this._adUnit.off; removeEventListener.call(this._adUnit, evtName, handler); }; VPAIDAdUnitWrapper.prototype.waitForEvent = function (evtName, cb, context) { let timeoutId; sanityCheck(evtName, cb); context = context || null; this.on(evtName, responseListener); timeoutId = setTimeout(() => { cb(new VASTError('on VPAIDAdUnitWrapper.waitForEvent, timeout while waiting for event \'' + evtName + '\'')); timeoutId = null; cb = utilities.noop; }, this.options.responseTimeout); /** * Local functions ***/ function sanityCheck (evtName, cb) { if (!utilities.isString(evtName)) { throw new VASTError('on VPAIDAdUnitWrapper.waitForEvent, missing evt name'); } if (!utilities.isFunction(cb)) { throw new VASTError('on VPAIDAdUnitWrapper.waitForEvent, missing callback'); } } function responseListener () { const args = utilities.arrayLikeObjToArray(arguments); if (timeoutId) { clearTimeout(timeoutId); timeoutId = null; } args.unshift(null); cb.apply(context, args); } }; // VPAID METHODS VPAIDAdUnitWrapper.prototype.handshakeVersion = function (version, cb) { this.adUnitAsyncCall('handshakeVersion', version, cb); }; /* jshint maxparams:6 */ VPAIDAdUnitWrapper.prototype.initAd = function (width, height, viewMode, desiredBitrate, adUnitData, cb) { this.waitForEvent('AdLoaded', cb); this._adUnit.initAd(width, height, viewMode, desiredBitrate, adUnitData); }; VPAIDAdUnitWrapper.prototype.resizeAd = function (width, height, viewMode, cb) { // NOTE: AdSizeChange event is only supported on VPAID 2.0 so for the moment we are not going to use it // and will assume that everything is fine after the async call this.adUnitAsyncCall('resizeAd', width, height, viewMode, cb); }; VPAIDAdUnitWrapper.prototype.startAd = function (cb) { this.waitForEvent('AdStarted', cb); this._adUnit.startAd(); }; VPAIDAdUnitWrapper.prototype.stopAd = function (cb) { this.waitForEvent('AdStopped', cb); this._adUnit.stopAd(); }; VPAIDAdUnitWrapper.prototype.pauseAd = function (cb) { this.waitForEvent('AdPaused', cb); this._adUnit.pauseAd(); }; VPAIDAdUnitWrapper.prototype.resumeAd = function (cb) { this.waitForEvent('AdPlaying', cb); this._adUnit.resumeAd(); }; VPAIDAdUnitWrapper.prototype.expandAd = function (cb) { this.waitForEvent('AdExpandedChange', cb); this._adUnit.expandAd(); }; VPAIDAdUnitWrapper.prototype.collapseAd = function (cb) { this.waitForEvent('AdExpandedChange', cb); this._adUnit.collapseAd(); }; VPAIDAdUnitWrapper.prototype.skipAd = function (cb) { this.waitForEvent('AdSkipped', cb); this._adUnit.skipAd(); }; // VPAID property getters [ 'adLinear', 'adWidth', 'adHeight', 'adExpanded', 'adSkippableState', 'adRemainingTime', 'adDuration', 'adVolume', 'adCompanions', 'adIcons' ].forEach((property) => { const getterName = 'get' + utilities.capitalize(property); VPAIDAdUnitWrapper.prototype[getterName] = function (cb) { this.adUnitAsyncCall(getterName, cb); }; }); // VPAID property setters VPAIDAdUnitWrapper.prototype.setAdVolume = function (volume, cb) { this.adUnitAsyncCall('setAdVolume', volume, cb); }; module.exports = VPAIDAdUnitWrapper;