-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
8 changed files
with
738 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# HbbTV Linear Sample App with IMA HTML5 DAI SDK | ||
|
||
This HbbTV linear sample app demonstrates the IMA HTML5 DAI SDK integration. It | ||
uses HbbTV stream events for detecting ad breaks and | ||
[dash.js](https://github.com/Dash-Industry-Forum/dash.js/) | ||
(version 4.6.0 or later) for ad playback. This application is intended to run | ||
as an HbbTV app on a compatible device. | ||
|
||
## Key Features | ||
|
||
* **Stream Events:** The app listens for HbbTV broadcast events of upcoming ad | ||
breaks. | ||
* **Preloading:** The app initiates DAI pod serving ad requests and passes the | ||
ad pod manifest to dash.js for preloading. | ||
* **Ad Break Handling:** The app listens for HbbTV events to switch from the | ||
broadcast stream to play the broadband ad break and resumes seamlessly | ||
afterward. | ||
|
||
## Requirements | ||
|
||
* HbbTV-compliant device | ||
* dash.js version 4.6.0 or later | ||
* Web server to host the application | ||
|
||
## Testing Environment Setup | ||
|
||
1. **Broadcast Stream:** Prepare an audio/video stream containing custom AIT | ||
(Application Information Table) data. | ||
2. **DVB Modulator:** Configure a DVB modulator to transmit the broadcast stream | ||
for reception by the hybrid terminal. | ||
3. **Web Server:** Host the HbbTV application on a web server accessible by the | ||
hybrid terminal. | ||
|
||
For detailed instructions on setting up your testing environment, refer to this | ||
guide on [running an HbbTV application](https://developer.hbbtv.org/tutorials/running-a-hbbtv-application-on-a-hybrid-terminal/). | ||
|
||
## How to Run | ||
|
||
Set the `stream_event_id` to match your networks event ID in `streamevent.xml`. | ||
The IMA team used the value `1` for testing this app. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
/* | ||
Copyright 2024 Google LLC | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
https://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
var POD_DURATION = 90000; // Ad pod duration in millisecond. | ||
|
||
/** | ||
* Wraps IMA SDK ad stream manager. | ||
* @param {!VideoPlayer} videoPlayer Reference an instance of the wrapper from | ||
* video_player.js. | ||
*/ | ||
var AdManager = function(videoPlayer) { | ||
this.streamData = null; | ||
this.videoPlayer = videoPlayer; | ||
// Ad UI is not supported for HBBTV, so no 'adUiElement' is passed in the | ||
// StreamManager constructor. | ||
this.streamManager = new google.ima.dai.api.StreamManager( | ||
this.videoPlayer.videoElement); | ||
this.streamManager.addEventListener( | ||
[ | ||
google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED, | ||
google.ima.dai.api.StreamEvent.Type.ERROR, | ||
google.ima.dai.api.StreamEvent.Type.CLICK, | ||
google.ima.dai.api.StreamEvent.Type.STARTED, | ||
google.ima.dai.api.StreamEvent.Type.FIRST_QUARTILE, | ||
google.ima.dai.api.StreamEvent.Type.MIDPOINT, | ||
google.ima.dai.api.StreamEvent.Type.THIRD_QUARTILE, | ||
google.ima.dai.api.StreamEvent.Type.COMPLETE, | ||
google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED, | ||
google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED, | ||
google.ima.dai.api.StreamEvent.Type.AD_PROGRESS, | ||
google.ima.dai.api.StreamEvent.Type.PAUSED, | ||
google.ima.dai.api.StreamEvent.Type.RESUMED | ||
], | ||
this.onStreamEvent.bind(this), | ||
false); | ||
|
||
this.videoPlayer.setEmsgEventHandler(this.onEmsgEvent, this); | ||
}; | ||
|
||
/** | ||
* Makes a pod stream request. | ||
* @param {string} networkCode The network code. | ||
* @param {string} customAssetKey The custom asset key. | ||
*/ | ||
AdManager.prototype.requestStream = function(networkCode, customAssetKey) { | ||
var streamRequest = new google.ima.dai.api.PodStreamRequest(); | ||
streamRequest.networkCode = networkCode; | ||
streamRequest.customAssetKey = customAssetKey; | ||
debugView.log('AdsManager: make PodStreamRequest'); | ||
this.streamManager.requestStream(streamRequest); | ||
}; | ||
|
||
/** | ||
* Handles IMA playback events. | ||
* @param {!Event} event The event object. | ||
*/ | ||
AdManager.prototype.onStreamEvent = function(event) { | ||
switch (event.type) { | ||
// Once the stream response data is received, generate pod manifest url | ||
// for the video stream. | ||
case google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED: | ||
debugView.log('IMA SDK: stream initialized'); | ||
this.streamData = event.getStreamData(); | ||
break; | ||
case google.ima.dai.api.StreamEvent.Type.ERROR: | ||
break; | ||
// Hide video controls while ad is playing. | ||
case google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED: | ||
debugView.log('IMA SDK: ad break started'); | ||
this.adPlaying = true; | ||
this.adBreakStarted = true; | ||
break; | ||
// Show video controls when ad ends. | ||
case google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED: | ||
debugView.log('IMA SDK: ad break ended'); | ||
this.adPlaying = false; | ||
this.adBreakStarted = false; | ||
break; | ||
// Update ad countdown timers. | ||
case google.ima.dai.api.StreamEvent.Type.AD_PROGRESS: | ||
break; | ||
default: | ||
debugView.log('IMA SDK: ' + event.type); | ||
break; | ||
} | ||
}; | ||
|
||
/** | ||
* Callback on Emsg event. | ||
* Instructs IMA SDK to fire back VAST events accordingly. | ||
* @param {!Event} event The event object. | ||
*/ | ||
AdManager.prototype.onEmsgEvent = function(event) { | ||
var data = event.event.messageData; | ||
var pts = event.event.calculatedPresentationTime; | ||
if ((data instanceof Uint8Array) && data.byteLength > 0) { | ||
this.streamManager.processMetadata('ID3', data, pts); | ||
} | ||
}; | ||
|
||
/** | ||
* Creates DAI pod url and instructs video player to load manifest. | ||
*/ | ||
AdManager.prototype.loadAdPodManifest = function() { | ||
if (!this.streamData) { | ||
debugView.log('IMA SDK: No DAI pod session registered.'); | ||
return; | ||
} | ||
|
||
var manifestUrl = this.streamData.getStandalonePodManifestUrl( | ||
this.getPodId(), POD_DURATION); | ||
this.videoPlayer.preload(manifestUrl); | ||
}; | ||
|
||
/** | ||
* Helper Function to get an unused pod ID. | ||
* In production the pod ID is determined by an Early Break Notification Call. | ||
* @return {string} The ad pod ID. | ||
*/ | ||
AdManager.prototype.getPodId = function() { | ||
return Math.trunc(new Date().getTime() / 60000); | ||
}; |
Oops, something went wrong.