Skip to content

Commit

Permalink
feat(FEC-10041): Allow ADS to be used in parallel (#54)
Browse files Browse the repository at this point in the history
Issue: load promise return the incorrect promise.
ima dai SDK fires ad_break_start and ad_start after load and before play request.
Solution: return a new promise on load which resolves or rejects on engine load rejection or resolves.
delay the ima dai SDK event to fires after play instead of the incorrect event after load which causes incorrect behavior on the player.

For the same video tag, we should use playAdsWithMSE.
  • Loading branch information
Yuvalke authored Feb 4, 2021
1 parent 4d25616 commit ea76bca
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 37 deletions.
44 changes: 24 additions & 20 deletions src/ima-dai-engine-decorator.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,22 @@ class ImaDAIEngineDecorator implements IEngineDecorator {
this._logger.debug('load', startTime);
// When load comes from a user gesture need to open the video element synchronously
this._engine.getVideoElement().load();
return this._plugin
.getStreamUrl()
.then(url => {
this._logger.debug('Stream url has been fetched', url);
this._loadStart = true;
this._engine.src = url;
return this._engine.load(this._plugin.getStreamTime(startTime));
})
.catch(e => {
this._logger.error(e);
this._plugin.destroy();
const loadPromise = this._engine.load(startTime);
this._active = false;
return loadPromise;
});
return new Promise((resolve, reject) => {
this._loadStart = true;
this._plugin.getStreamUrl().then(
url => {
this._logger.debug('Stream url has been fetched', url);
this._engine.src = url;
this._engine.load(this._plugin.getStreamTime(startTime)).then(resolve, reject);
},
e => {
this._logger.error(e);
this._plugin.destroy();
this._active = false;
this._engine.load(startTime).then(resolve, reject);
}
);
});
}

/**
Expand Down Expand Up @@ -111,7 +112,8 @@ class ImaDAIEngineDecorator implements IEngineDecorator {
if (this._plugin.isAdBreak()) {
this._plugin.resumeAd();
}
this._engine.play();
const playPromise = this._engine.play();
playPromise ? playPromise.then(() => this._plugin._dispatchEventsOnFirstPlay()) : this._plugin._dispatchEventsOnFirstPlay();
}

/**
Expand Down Expand Up @@ -211,6 +213,12 @@ class ImaDAIEngineDecorator implements IEngineDecorator {
_attachListeners(): void {
this._eventManager.listen(this._plugin.player, Html5EventType.PLAY, () => !this._plugin.isAdBreak() && (this._contentEnded = false));
this._eventManager.listen(this._plugin.player, AdEventType.AD_BREAK_START, event => this._onAdBreakStart(event));
this._eventManager.listenOnce(this._plugin.player, AdEventType.AD_LOADED, () => {
if (!this._loadStart) {
// preroll from another ad plugin (e.g. bumper)
this._active = false;
}
});
this._eventManager.listenOnce(this._plugin.player, AdEventType.AD_BREAK_END, () => (this._active = true));
}

Expand All @@ -219,10 +227,6 @@ class ImaDAIEngineDecorator implements IEngineDecorator {
if (adBreak.type === AdBreakType.POST) {
this._contentEnded = true;
}
if (!this._loadStart) {
// preroll from another ad plugin (e.g. bumper)
this._active = false;
}
}
}

Expand Down
7 changes: 1 addition & 6 deletions src/ima-dai-event-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,7 @@ class ImaDAIEventManager {
}

_onAdBreakEnd(): void {
if (this._queue.size() > 0) {
while (!this._queue.isEmpty()) {
const event = this._queue.pop();
this._dispatchEventHandler(event);
}
}
this._queue.dispatchAll(this._dispatchEventHandler);
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/ima-dai-event-queue.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ class ImaDAIEventQueue {
}
}

dispatchAll(dispatcher: Function): void {
if (this.size() > 0) {
while (!this.isEmpty()) {
const event = this.pop();
dispatcher(event);
}
}
}

isEmpty(): boolean {
return this.size() === 0;
}
Expand Down
34 changes: 23 additions & 11 deletions src/ima-dai.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {ImaDAIState} from './ima-dai-state';
import {ImaDAIEngineDecorator} from './ima-dai-engine-decorator';
import {ImaDAIAdsController} from './ima-dai-ads-controller';
import './assets/style.css';
import {ImaDAIEventQueue} from './ima-dai-event-queue';

const {Ad, AdBreak, AdBreakType, EventType, FakeEvent, Utils, Env} = core;
const ADS_CONTAINER_CLASS: string = 'playkit-dai-ads-container';
Expand Down Expand Up @@ -37,6 +38,8 @@ class ImaDAI extends BasePlugin implements IAdsControllerProvider, IEngineDecora
_adsCoverDivExists: boolean;
_snapback: boolean;
_ignorePreroll: boolean;
_queue: ImaDAIEventQueue;
_firstPlay: boolean;

static IMA_DAI_SDK_LIB_URL: string = '//imasdk.googleapis.com/js/sdkloader/ima3_dai.js';

Expand Down Expand Up @@ -274,6 +277,7 @@ class ImaDAI extends BasePlugin implements IAdsControllerProvider, IEngineDecora
}
});
this.eventManager.listen(this.player, EventType.CHANGE_SOURCE_ENDED, () => {
this.eventManager.listen(this.player, EventType.LOADED_METADATA, () => this._onLoadedMetadata());
this._attachEngineListeners();
});
this.eventManager.listen(this.player, EventType.TIME_UPDATE, () => {
Expand Down Expand Up @@ -307,14 +311,6 @@ class ImaDAI extends BasePlugin implements IAdsControllerProvider, IEngineDecora
}
}
});
this.eventManager.listen(this.player, EventType.PLAY_FAILED, () => {
if (this._adBreak) {
this._onAdBreakEnded();
this.eventManager.listenOnce(this.player, EventType.FIRST_PLAY, () => {
this._onAdBreakStarted();
});
}
});
}

_init(): void {
Expand All @@ -341,6 +337,8 @@ class ImaDAI extends BasePlugin implements IAdsControllerProvider, IEngineDecora
this._ignorePreroll = false;
this._playbackRate = 1;
this._snapback = this.config.snapback;
this._queue = new ImaDAIEventQueue();
this._firstPlay = false;
}

_loadImaDAILib(): Promise<*> {
Expand Down Expand Up @@ -382,7 +380,6 @@ class ImaDAI extends BasePlugin implements IAdsControllerProvider, IEngineDecora
}

_attachEngineListeners(): void {
this.eventManager.listen(this._engine, EventType.LOADED_METADATA, () => this._onLoadedMetadata());
this.eventManager.listen(this._engine, EventType.VOLUME_CHANGE, () => this._onVolumeChange());
this.eventManager.listen(this._engine, 'hlsFragParsingMetadata', event => this._onHlsFragParsingMetadata(event));
}
Expand Down Expand Up @@ -612,6 +609,7 @@ class ImaDAI extends BasePlugin implements IAdsControllerProvider, IEngineDecora
adOptions.position = podInfo.getAdPosition();
}
adOptions.bumper = false;
adOptions.inStream = true;
adOptions.linear = true;
return adOptions;
}
Expand Down Expand Up @@ -657,8 +655,22 @@ class ImaDAI extends BasePlugin implements IAdsControllerProvider, IEngineDecora
}

_dispatchAdEvent(type: string, payload?: Object): void {
this.logger.debug(type.toUpperCase(), payload);
this.dispatchEvent(type, payload);
if (!this._firstPlay) {
this._queue.push({type, payload});
} else {
this.logger.debug(type.toUpperCase(), payload);
this.dispatchEvent(type, payload);
}
}

_dispatchEventsOnFirstPlay(): void {
if (!this._firstPlay) {
this._firstPlay = true;
this._queue.dispatchAll(event => {
const {type, payload} = event;
this._dispatchAdEvent(type, payload);
});
}
}

_shouldPauseOnAdClick(): boolean {
Expand Down

0 comments on commit ea76bca

Please sign in to comment.