Skip to content

Commit

Permalink
feat(Ads): Add support for AWS Elemental MediaTailor (#5679)
Browse files Browse the repository at this point in the history
  • Loading branch information
avelad committed Sep 28, 2023
1 parent 756a576 commit cf5a72b
Show file tree
Hide file tree
Showing 16 changed files with 1,644 additions and 62 deletions.
10 changes: 10 additions & 0 deletions README.md
Expand Up @@ -298,6 +298,16 @@ Shaka Player supports:
- External WebVTT with images/sprites (only for VoD)


## Monetization with Ads

Shaka Player supports:
- IMA SDK for Client-Side Ad Insertion
- IMA DAI SDK for Server-Side Ad Insertion
- AWS MediaTailor for Client-Side
- AWS MediaTailor for Server-Side
- AWS MediaTailor overlays


## Documentation & Important Links ##

* [Demo](https://shaka-player-demo.appspot.com)([sources](demo/))
Expand Down
2 changes: 2 additions & 0 deletions build/types/ads
Expand Up @@ -4,5 +4,7 @@
+../../lib/ads/ads_stats.js
+../../lib/ads/client_side_ad.js
+../../lib/ads/client_side_ad_manager.js
+../../lib/ads/media_tailor_ad.js
+../../lib/ads/media_tailor_ad_manager.js
+../../lib/ads/server_side_ad.js
+../../lib/ads/server_side_ad_manager.js
19 changes: 19 additions & 0 deletions demo/common/asset.js
Expand Up @@ -78,6 +78,10 @@ const ShakaDemoAssetInfo = class {
/** @type {?string} */
this.imaManifestType = null;
/** @type {?string} */
this.mediaTailorUrl = null;
/** @type {?Object} */
this.mediaTailorAdsParams = null;
/** @type {?string} */
this.mimeType = null;
/** @type {?string} */
this.mediaPlaylistFullMimeType = null;
Expand Down Expand Up @@ -287,6 +291,21 @@ const ShakaDemoAssetInfo = class {
return this;
}

/**
* @param {string} url
* @param {?Object=} adsParams
* @return {!ShakaDemoAssetInfo}
*/
setMediaTailor(url, adsParams=null) {
this.mediaTailorUrl = url;
this.mediaTailorAdsParams = adsParams;
if (!this.features.includes(shakaAssets.Feature.ADS)) {
this.addFeature(shakaAssets.Feature.ADS);
}

return this;
}

/**
* @param {string} headerName
* @param {string} headerValue
Expand Down
59 changes: 59 additions & 0 deletions demo/common/assets.js
Expand Up @@ -40,6 +40,7 @@ shakaAssets.Source = {
IRT: 'IRT',
MICROSOFT: 'Microsoft',
VNOVA: 'V-Nova',
AWS: 'AWS',
};


Expand Down Expand Up @@ -1441,5 +1442,63 @@ shakaAssets.testAssets = [
},
}),
// }}}

// AWS assets {{{
/* MediaTailor Contents */
new ShakaDemoAssetInfo(
/* name= */ 'Media Tailor HLS',
/* iconUri= */ '',
/* manifestUri= */ 'https://ad391cc0d55b44c6a86d232548adc225.mediatailor.us-east-1.amazonaws.com/v1/session/d02fedbbc5a68596164208dd24e9b48aa60dadc7/singssai/master.m3u8',
/* source= */ shakaAssets.Source.AWS)
.addFeature(shakaAssets.Feature.HLS)
.addFeature(shakaAssets.Feature.HIGH_DEFINITION)
.addFeature(shakaAssets.Feature.MP2TS)
.setMediaTailor('https://ad391cc0d55b44c6a86d232548adc225.mediatailor.us-east-1.amazonaws.com/v1/session/d02fedbbc5a68596164208dd24e9b48aa60dadc7/singssai/master.m3u8'),
new ShakaDemoAssetInfo(
/* name= */ 'Media Tailor Live HLS',
/* iconUri= */ '',
/* manifestUri= */ 'https://d305rncpy6ne2q.cloudfront.net/v1/session/94063eadf7d8c56e9e2edd84fdf897826a70d0df/SFP-MediaTailor-Live-HLS-DASH/channel/sfp-channel1/hls.m3u8',
/* source= */ shakaAssets.Source.AWS)
.addFeature(shakaAssets.Feature.HLS)
.addFeature(shakaAssets.Feature.HIGH_DEFINITION)
.addFeature(shakaAssets.Feature.MP2TS)
.addFeature(shakaAssets.Feature.LIVE)
.setMediaTailor('https://d305rncpy6ne2q.cloudfront.net/v1/session/94063eadf7d8c56e9e2edd84fdf897826a70d0df/SFP-MediaTailor-Live-HLS-DASH/channel/sfp-channel1/hls.m3u8'),
new ShakaDemoAssetInfo(
/* name= */ 'Media Tailor DASH',
/* iconUri= */ '',
/* manifestUri= */ 'https://d305rncpy6ne2q.cloudfront.net/v1/session/94063eadf7d8c56e9e2edd84fdf897826a70d0df/SFP-MediaTailor-VOD-HLS-DASH/out/v1/b94f3611978f419985a18335bac9d9cb/ddb73bf548a44551a0059c346226445a/eaa5485198bf497284559efb8172425e/index.mpd',
/* source= */ shakaAssets.Source.AWS)
.addFeature(shakaAssets.Feature.DASH)
.addFeature(shakaAssets.Feature.HIGH_DEFINITION)
.addFeature(shakaAssets.Feature.MP4)
.setMediaTailor('https://d305rncpy6ne2q.cloudfront.net/v1/session/94063eadf7d8c56e9e2edd84fdf897826a70d0df/SFP-MediaTailor-VOD-HLS-DASH/out/v1/b94f3611978f419985a18335bac9d9cb/ddb73bf548a44551a0059c346226445a/eaa5485198bf497284559efb8172425e/index.mpd',
{
adsParams: {
assetid: 'test2',
podduration: '15',
},
}),
new ShakaDemoAssetInfo(
/* name= */ 'Media Tailor Live DASH',
/* iconUri= */ '',
/* manifestUri= */ 'https://d305rncpy6ne2q.cloudfront.net/v1/session/94063eadf7d8c56e9e2edd84fdf897826a70d0df/SFP-MediaTailor-Live-HLS-DASH/channel/sfp-channel1/dash.mpd',
/* source= */ shakaAssets.Source.AWS)
.addFeature(shakaAssets.Feature.DASH)
.addFeature(shakaAssets.Feature.HIGH_DEFINITION)
.addFeature(shakaAssets.Feature.MP4)
.addFeature(shakaAssets.Feature.LIVE)
.setMediaTailor('https://d305rncpy6ne2q.cloudfront.net/v1/session/94063eadf7d8c56e9e2edd84fdf897826a70d0df/SFP-MediaTailor-Live-HLS-DASH/channel/sfp-channel1/dash.mpd'),
new ShakaDemoAssetInfo(
/* name= */ 'Media Tailor Live HLS with overlays',
/* iconUri= */ '',
/* manifestUri= */ 'https://d305rncpy6ne2q.cloudfront.net/v1/session/94063eadf7d8c56e9e2edd84fdf897826a70d0df/SFP-MediaTailor-Live-HLS-Overlays/channel/sfp-channel2/hls.m3u8',
/* source= */ shakaAssets.Source.AWS)
.addFeature(shakaAssets.Feature.HLS)
.addFeature(shakaAssets.Feature.HIGH_DEFINITION)
.addFeature(shakaAssets.Feature.MP2TS)
.addFeature(shakaAssets.Feature.LIVE)
.setMediaTailor('https://d305rncpy6ne2q.cloudfront.net/v1/session/94063eadf7d8c56e9e2edd84fdf897826a70d0df/SFP-MediaTailor-Live-HLS-Overlays/channel/sfp-channel2/hls.m3u8'),
// }}}
];
/* eslint-enable max-len */
33 changes: 33 additions & 0 deletions demo/main.js
Expand Up @@ -1245,6 +1245,11 @@ shakaDemo.Main = class {
if (asset.imaAssetKey || (asset.imaContentSrcId && asset.imaVideoId)) {
manifestUri = await this.getManifestUriFromAdManager_(asset);
}
// If it's a MediaTailor asset, request ad-containing manifest
// from the ad manager.
if (asset.mediaTailorUrl) {
manifestUri = await this.getManifestUriFromMediaTailorAdManager_(asset);
}
await this.player_.load(
manifestUri,
/* startTime= */ null,
Expand Down Expand Up @@ -1532,6 +1537,34 @@ shakaDemo.Main = class {
}
}

/**
* @param {ShakaDemoAssetInfo} asset
* @return {!Promise.<string>}
* @private
*/
async getManifestUriFromMediaTailorAdManager_(asset) {
const adManager = this.player_.getAdManager();
const container = this.controls_.getServerSideAdContainer();
try {
goog.asserts.assert(this.video_ != null, 'Video should not be null!');
goog.asserts.assert(asset.mediaTailorUrl != null,
'Media Tailor info not be null!');
const netEngine = this.player_.getNetworkingEngine();
goog.asserts.assert(netEngine, 'There should be a net engine.');
adManager.initMediaTailor(container, netEngine, this.video_);
const uri = await adManager.requestMediaTailorStream(
asset.mediaTailorUrl, asset.mediaTailorAdsParams,
/* backupUri= */ asset.manifestUri);
return uri;
} catch (error) {
console.log(error);
console.warn('Ads code has been prevented from running ' +
'or returned an error. Proceeding without ads.');

return asset.manifestUri;
}
}

/**
* Sets up a nav button, and an associated tab.
* This method is meant to be called by the various tabs, as part of their
Expand Down
193 changes: 193 additions & 0 deletions externs/mediatailor.js
@@ -0,0 +1,193 @@
/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

/**
* @fileoverview Externs for Media Tailor.
* @externs
*/


/** @const */
var mediaTailor = {};


/**
* @typedef {{
* manifestUrl: ?string,
* trackingUrl: ?string
* }}
*
* @property {?string} manifestUrl
* @property {?string} trackingUrl
* @exportDoc
*/
mediaTailor.SessionResponse;


/**
* @typedef {{
* avails: !Array.<mediaTailor.AdBreak>
* }}
*
* @property {!Array.<mediaTailor.AdBreak>} avails
* @exportDoc
*/
mediaTailor.TrackingResponse;


/**
* @typedef {{
* adBreakTrackingEvents: !Array.<mediaTailor.TrackingEvent>,
* ads: !Array.<mediaTailor.Ad>,
* durationInSeconds: number,
* nonLinearAdsList: !Array.<mediaTailor.Ad>,
* startTimeInSeconds: number
* }}
*
* @property {!Array.<mediaTailor.TrackingEvent>} adBreakTrackingEvents
* @property {!Array.<mediaTailor.Ad>} ads
* @property {number} durationInSeconds
* @property {!Array.<mediaTailor.Ad>} nonLinearAdsList
* @property {number} startTimeInSeconds
* @exportDoc
*/
mediaTailor.AdBreak;


/**
* @typedef {{
* adId: string,
* adParameters: string,
* adSystem: string,
* adTitle: string,
* creativeId: string,
* creativeSequence: string,
* durationInSeconds: number,
* skipOffset: ?number,
* startTimeInSeconds: number,
* nonLinearAdList: !Array.<mediaTailor.NonLinearAd>,
* trackingEvents: !Array.<mediaTailor.TrackingEvent>
* }}
*
* @property {string} adId
* @property {string} adParameters
* @property {string} adSystem
* @property {string} adTitle
* @property {string} creativeId
* @property {string} creativeSequence
* @property {number} durationInSeconds
* @property {?number} skipOffset
* @property {number} startTimeInSeconds
* @property {!Array.<mediaTailor.NonLinearAd>} nonLinearAdList
* @property {!Array.<mediaTailor.TrackingEvent>} trackingEvents
* @exportDoc
*/
mediaTailor.Ad;


/**
* @typedef {{
* adId: string,
* adParameters: string,
* adSystem: string,
* adTitle: string,
* creativeAdId: string,
* creativeId: string,
* creativeSequence: string,
* height: ?number,
* width: ?number,
* staticResource: string
* }}
*
* @property {string} adId
* @property {string} adParameters
* @property {string} adSystem
* @property {string} adTitle
* @property {string} creativeAdId
* @property {string} creativeId
* @property {string} creativeSequence
* @property {?number} height
* @property {?number} width
* @property {string} staticResource
* @exportDoc
*/
mediaTailor.NonLinearAd;


/**
* @typedef {{
* beaconUrls: !Array.<string>,
* eventType: string
* }}
*
* @property {!Array.<string>} beaconUrls
* @property {string} eventType
* @exportDoc
*/
mediaTailor.TrackingEvent;


/** @const */
var mediaTailorExternalResource = {};


/**
* @typedef {{
* apps: !Array.<mediaTailorExternalResource.App>
* }}
*
* @property {!Array.<mediaTailorExternalResource.App>} apps
* @exportDoc
*/
mediaTailorExternalResource.Response;


/**
* @typedef {{
* placeholder: mediaTailorExternalResource.AppPlaceholder,
* data: mediaTailorExternalResource.AppData
* }}
*
* @property {mediaTailorExternalResource.AppPlaceholder} placeholder
* @property {mediaTailorExternalResource.AppData} data
* @exportDoc
*/
mediaTailorExternalResource.App;


/**
* @typedef {{
* left: number,
* top: number
* }}
*
* @property {number} left
* @property {number} top
* @exportDoc
*/
mediaTailorExternalResource.AppPlaceholder;


/**
* @typedef {{
* source: !Array.<mediaTailorExternalResource.AppDataSource>
* }}
*
* @property {!Array.<mediaTailorExternalResource.AppDataSource>} source
* @exportDoc
*/
mediaTailorExternalResource.AppData;


/**
* @typedef {{
* url: string
* }}
*
* @property {string} url
* @exportDoc
*/
mediaTailorExternalResource.AppDataSource;

0 comments on commit cf5a72b

Please sign in to comment.