Skip to content

Commit a6f3999

Browse files
authored
feat(Ads): Add basic VMAP support without IMA (#7054)
1 parent c59922b commit a6f3999

File tree

2 files changed

+74
-14
lines changed

2 files changed

+74
-14
lines changed

lib/ads/ad_utils.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,47 @@ shaka.ads.Utils = class {
9696
}
9797
return interstitials;
9898
}
99+
100+
/**
101+
* @param {!shaka.extern.xml.Node} vmap
102+
* @return {!Array.<{time: ?number, uri: string}>}
103+
*/
104+
static parseVMAP(vmap) {
105+
const TXml = shaka.util.TXml;
106+
/** @type {!Array.<{time: ?number, uri: string}>} */
107+
const ads = [];
108+
for (const adBreak of TXml.findChildren(vmap, 'vmap:AdBreak')) {
109+
const timeOffset = adBreak.attributes['timeOffset'];
110+
if (!timeOffset) {
111+
continue;
112+
}
113+
let time = null;
114+
if (timeOffset == 'start') {
115+
time = 0;
116+
} else if (timeOffset == 'end') {
117+
time = Infinity;
118+
} else {
119+
time = shaka.util.TextParser.parseTime(timeOffset);
120+
}
121+
const adSource = TXml.findChild(adBreak, 'vmap:AdSource');
122+
if (!adSource) {
123+
continue;
124+
}
125+
const adTagURI = TXml.findChild(adSource, 'vmap:AdTagURI');
126+
if (!adTagURI) {
127+
continue;
128+
}
129+
const uri = TXml.getTextContents(adTagURI);
130+
if (!uri) {
131+
continue;
132+
}
133+
ads.push({
134+
time,
135+
uri,
136+
});
137+
}
138+
return ads;
139+
}
99140
};
100141

101142
/**

lib/ads/interstitial_ad_manager.js

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,8 @@ shaka.ads.InterstitialAdManager = class {
230230
* @return {!Promise}
231231
*/
232232
async addAdUrlInterstitial(url) {
233-
const type = shaka.net.NetworkingEngine.RequestType.ADS;
234-
const request = shaka.net.NetworkingEngine.makeRequest(
235-
[url],
236-
shaka.net.NetworkingEngine.defaultRetryParameters());
237-
const op = this.basePlayer_.getNetworkingEngine().request(type, request);
238-
const response = await op.promise;
239-
const data = shaka.util.TXml.parseXml(response.data, 'VAST,vmap:VMAP');
233+
const responseData = await this.makeAdRequest_(url);
234+
const data = shaka.util.TXml.parseXml(responseData, 'VAST,vmap:VMAP');
240235
if (!data) {
241236
throw new shaka.util.Error(
242237
shaka.util.Error.Severity.CRITICAL,
@@ -247,6 +242,20 @@ shaka.ads.InterstitialAdManager = class {
247242
if (data.tagName == 'VAST') {
248243
interstitials = shaka.ads.Utils.parseVastToInterstitials(
249244
data, this.lastTime_);
245+
} else if (data.tagName == 'vmap:VMAP') {
246+
for (const ad of shaka.ads.Utils.parseVMAP(data)) {
247+
// eslint-disable-next-line no-await-in-loop
248+
const vastResponseData = await this.makeAdRequest_(ad.uri);
249+
const vast = shaka.util.TXml.parseXml(vastResponseData, 'VAST');
250+
if (!vast) {
251+
throw new shaka.util.Error(
252+
shaka.util.Error.Severity.CRITICAL,
253+
shaka.util.Error.Category.ADS,
254+
shaka.util.Error.Code.VAST_INVALID_XML);
255+
}
256+
interstitials.push(...shaka.ads.Utils.parseVastToInterstitials(
257+
vast, ad.time));
258+
}
250259
}
251260
this.addInterstitials(interstitials);
252261
}
@@ -705,14 +714,9 @@ shaka.ads.InterstitialAdManager = class {
705714
if (!uri) {
706715
return interstitialsAd;
707716
}
708-
const type = shaka.net.NetworkingEngine.RequestType.ADS;
709-
const request = shaka.net.NetworkingEngine.makeRequest(
710-
[uri],
711-
shaka.net.NetworkingEngine.defaultRetryParameters());
712-
const op = this.basePlayer_.getNetworkingEngine().request(type, request);
713717
try {
714-
const response = await op.promise;
715-
const data = shaka.util.StringUtils.fromUTF8(response.data);
718+
const responseData = await this.makeAdRequest_(uri);
719+
const data = shaka.util.StringUtils.fromUTF8(responseData);
716720
const dataAsJson =
717721
/** @type {!shaka.ads.InterstitialAdManager.AssetsList} */ (
718722
JSON.parse(data));
@@ -791,6 +795,21 @@ shaka.ads.InterstitialAdManager = class {
791795
netEngine.clearAllResponseFilters();
792796
this.basePlayer_.getNetworkingEngine().copyFiltersInto(netEngine);
793797
}
798+
799+
/**
800+
* @param {string} url
801+
* @return {!Promise.<BufferSource>}
802+
* @private
803+
*/
804+
async makeAdRequest_(url) {
805+
const type = shaka.net.NetworkingEngine.RequestType.ADS;
806+
const request = shaka.net.NetworkingEngine.makeRequest(
807+
[url],
808+
shaka.net.NetworkingEngine.defaultRetryParameters());
809+
const op = this.basePlayer_.getNetworkingEngine().request(type, request);
810+
const response = await op.promise;
811+
return response.data;
812+
}
794813
};
795814

796815

0 commit comments

Comments
 (0)