diff --git a/demo/common/message_ids.js b/demo/common/message_ids.js
index ebec947d9e..99de27b8a2 100644
--- a/demo/common/message_ids.js
+++ b/demo/common/message_ids.js
@@ -153,6 +153,7 @@ shakaDemo.MessageIds = {
/* Config panel. */
ADAPTATION_RESTRICTIONS_SECTION_HEADER: 'DEMO_ADAPTATION_RESTRICTIONS_SECTION_HEADER',
ADAPTATION_SECTION_HEADER: 'DEMO_ADAPTATION_SECTION_HEADER',
+ ADS_SECTION_HEADER: 'DEMO_ADS_SECTION_HEADER',
ALWAYS_STREAM_TEXT: 'DEMO_ALWAYS_STREAM_TEXT',
ALWAYS_STREAM_TEXT_WARNING: 'DEMO_ALWAYS_STREAM_TEXT_WARNING',
AUDIO_CHANNEL_COUNT: 'DEMO_AUDIO_CHANNEL_COUNT',
@@ -179,6 +180,7 @@ shakaDemo.MessageIds = {
CMCD_SECTION_HEADER: 'DEMO_CMCD_SECTION_HEADER',
CONNECTION_TIMEOUT: 'DEMO_CONNECTION_TIMEOUT',
CONTENT_ID: 'DEMO_CONTENT_ID',
+ CUSTOM_PLAYHEAD_TRACKER: 'DEMO_CUSTOM_PLAYHEAD_TRACKER',
DASH_SEQUENCE_MODE: 'DEMO_DASH_SEQUENCE_MODE',
DEFAULT_AUDIO_CODEC: 'DEMO_DEFAULT_AUDIO_CODEC',
DEFAULT_PRESENTATION_DELAY: 'DEMO_DEFAULT_PRESENTATION_DELAY',
diff --git a/demo/config.js b/demo/config.js
index 6070b3c36f..568dd5e0a2 100644
--- a/demo/config.js
+++ b/demo/config.js
@@ -98,6 +98,7 @@ shakaDemo.Config = class {
shakaDemo.MessageIds.RESTRICTIONS_SECTION_HEADER);
this.addCmcdSection_();
this.addLcevcSection_();
+ this.addAdsSection_();
}
/**
@@ -328,6 +329,15 @@ shakaDemo.Config = class {
.addBoolInput_(MessageIds.LCEVC_DRAW_LOGO, 'lcevc.drawLogo');
}
+ /** @private */
+ addAdsSection_() {
+ const MessageIds = shakaDemo.MessageIds;
+ const docLink = this.resolveExternLink_('.AdsConfiguration');
+ this.addSection_(MessageIds.ADS_SECTION_HEADER, docLink)
+ .addBoolInput_(MessageIds.CUSTOM_PLAYHEAD_TRACKER,
+ 'ads.customPlayheadTracker');
+ }
+
/**
* @param {string} category
* @param {!shakaDemo.MessageIds} sectionName
diff --git a/demo/locales/en.json b/demo/locales/en.json
index 044476e90a..13c9bdb287 100644
--- a/demo/locales/en.json
+++ b/demo/locales/en.json
@@ -5,6 +5,7 @@
"DEMO_AD_SEARCH": "Filters for assets that have advertisements.",
"DEMO_AD_TAG_URL": "Ad Tag URL",
"DEMO_ADS_TAB": "Ads",
+ "DEMO_ADS_SECTION_HEADER": "Ads",
"DEMO_ALL_CONTENT": "ALL CONTENT",
"DEMO_ALWAYS_STREAM_TEXT": "Always Stream Text",
"DEMO_ALWAYS_STREAM_TEXT_WARNING": "Text must always be streamed while native controls are enabled, for captions to work.",
@@ -53,6 +54,7 @@
"DEMO_CUSTOM_INTRO_ONE": "Try Shaka Player with your own content!",
"DEMO_CUSTOM_INTRO_THREE": "Custom assets will remain even after reloading the page.",
"DEMO_CUSTOM_INTRO_TWO": "Press the button below to add a custom asset.",
+ "DEMO_CUSTOM_PLAYHEAD_TRACKER": "Custom playhead tracker",
"DEMO_DASH": "DASH",
"DEMO_DASH_IF": "DASH-IF",
"DEMO_DASH_SEQUENCE_MODE": "Enable DASH sequence mode",
diff --git a/demo/locales/source.json b/demo/locales/source.json
index 87ddde1b7b..be6c8e64c0 100644
--- a/demo/locales/source.json
+++ b/demo/locales/source.json
@@ -15,6 +15,10 @@
"description": "The header for a tab within the custom asset creation dialog.",
"message": "Ads"
},
+ "DEMO_ADS_SECTION_HEADER": {
+ "description": "The header for a section of configuration values.",
+ "message": "Ads"
+ },
"DEMO_AD_SEARCH": {
"description": "A tooltip for an optional search term.",
"message": "Filters for assets that have advertisements."
@@ -215,6 +219,10 @@
"description": "The second part of a message instructing users on how to add custom content.",
"message": "Press the button below to add a custom asset."
},
+ "DEMO_CUSTOM_PLAYHEAD_TRACKER": {
+ "description": "The name of a configuration value.",
+ "message": "Custom playhead tracker"
+ },
"DEMO_DASH": {
"description": "Text that describes an asset that is packaged in a DASH manifest.",
"message": "[PROPER_NAME:DASH]"
diff --git a/externs/ima.js b/externs/ima.js
index 0db047e385..b23fb10bd3 100644
--- a/externs/ima.js
+++ b/externs/ima.js
@@ -119,7 +119,7 @@ google.ima.AdsManager = class {
/** @const */
google.ima.AdsManagerLoadedEvent = class extends Event {
/**
- * @param {!HTMLElement} video
+ * @param {!(HTMLElement|{currentTime: number})} video
* @param {!google.ima.AdsRenderingSettings=} adsRenderingSettings
* @return {!google.ima.AdsManager}
*/
diff --git a/externs/shaka/player.js b/externs/shaka/player.js
index bf0a684820..2d6d79b6ba 100644
--- a/externs/shaka/player.js
+++ b/externs/shaka/player.js
@@ -1246,11 +1246,19 @@ shaka.extern.MediaSourceConfiguration;
/**
- * @typedef {Object}
+ * @typedef {{
+ * customPlayheadTracker: boolean
+ * }}
*
* @description
* Ads configuration.
*
+ * @property {boolean} customPlayheadTracker
+ * If this is true
, we create a custom playhead tracker for
+ * Client Side. This is useful because it allows you to implement the use of
+ * IMA on platforms that do not support multiple video elements.
+ * This value defaults to false
.
+ *
* @exportDoc
*/
shaka.extern.AdsConfiguration;
diff --git a/lib/ads/client_side_ad_manager.js b/lib/ads/client_side_ad_manager.js
index 6270608e1c..d564ff5d35 100644
--- a/lib/ads/client_side_ad_manager.js
+++ b/lib/ads/client_side_ad_manager.js
@@ -206,8 +206,37 @@ shaka.ads.ClientSideAdManager = class {
this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.ADS_LOADED,
(new Map()).set('loadTime', loadTime)));
- this.imaAdsManager_ = e.getAdsManager(this.video_,
- this.adsRenderingSettings_);
+ if (!this.config_.customPlayheadTracker) {
+ this.imaAdsManager_ = e.getAdsManager(this.video_,
+ this.adsRenderingSettings_);
+ } else {
+ const videoPlayHead = {
+ currentTime: this.video_.currentTime,
+ };
+
+ this.imaAdsManager_ = e.getAdsManager(videoPlayHead,
+ this.adsRenderingSettings_);
+
+ if (this.video_.muted) {
+ this.imaAdsManager_.setVolume(0);
+ } else {
+ this.imaAdsManager_.setVolume(this.video_.volume);
+ }
+
+ this.eventManager_.listen(this.video_, 'timeupdate', () => {
+ if (!this.video_.duration) {
+ return;
+ }
+ videoPlayHead.currentTime = this.video_.currentTime;
+ });
+ this.eventManager_.listen(this.video_, 'volumechange', () => {
+ if (this.video_.muted) {
+ this.imaAdsManager_.setVolume(0);
+ } else {
+ this.imaAdsManager_.setVolume(this.video_.volume);
+ }
+ });
+ }
this.onEvent_(new shaka.util.FakeEvent(
shaka.ads.AdManager.IMA_AD_MANAGER_LOADED,
diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js
index 6233a9349e..d1a1696ec1 100644
--- a/lib/util/player_configuration.js
+++ b/lib/util/player_configuration.js
@@ -312,7 +312,9 @@ shaka.util.PlayerConfiguration = class {
forceTransmux: false,
};
- const ads = {};
+ const ads = {
+ customPlayheadTracker: false,
+ };
const AutoShowText = shaka.config.AutoShowText;