@harmonicinc/vos_roku_rafx_ssai
v0.0.19
Published
Harmonic VOS RAFX SSAI adapter for Roku apps
Keywords
Readme
Harmonic RAFX SSAI adapter
Installation
Native BrightScript only
Download latest release transpiled in BrightScript: hlit-rafx-ssai-brs.zip
Copy all files inside
/sourceto<your_app_root>/source/hlit-rafx-ssai/Dependencies are included under
/source/roku_modules, so there's no need to install them separately.You should get something like this:
└── source ├── hlit_rafx_ssai │ ├── DashParser.brs │ ├── MetadataParser.brs │ ├── PodHelper.brs │ ├── SSAI.brs │ └── roku_modules │ ├── bslib │ │ └── bslib.brs │ └── rokurequests │ └── Requests.brs └── main.brsCreate a new task component that is responsible for player control & client-side ad tracking. You may use existing ones if you already have one in your app.
For example, in Tasks folder in the example app, we have a dedicated
PlayerTaskto handle player-related functionsImport required libraries
In your task component XML, import required libraries.
<script type="text/brightscript" uri="pkg:/source/hlit_rafx_ssai/SSAI.brs" /> <script type="text/brightscript" uri="pkg:/source/hlit_rafx_ssai/PodHelper.brs" /> <script type="text/brightscript" uri="pkg:/source/hlit_rafx_ssai/MetadataParser.brs" /> <script type="text/brightscript" uri="pkg:/source/hlit_rafx_ssai/DashParser.brs" /> <script type="text/brightscript" uri="pkg:/source/hlit_rafx_ssai/roku_modules/rokurequests/Requests.brs" /> <script type="text/brightscript" uri="pkg:/source/hlit_rafx_ssai/roku_modules/bslib/bslib.brs" />Import Roku RAF library in your BrightScript file
library "Roku_Ads.brs"
Using ropm & BrighterScript
ropm package manager is supported. Install it by
ropm install @harmonicinc/vos_roku_rafx_ssaiCreate a new task component that is responsible for player control & client-side ad tracking. You may use existing ones if you already have one in your app.
For example, in Tasks folder in the example app, we have a dedicated PlayerTask.bs to handle player-related functions
Import required libraries in your BrighterScript file
import "pkg:/source/roku_modules/harmonicinc_vos_roku_rafx_ssai/ssai.bs" library "Roku_Ads.brs"
Usage
Create Harmonic RAFX adapter by
adapter = new harmonic.rafx.ssai.RAFX_SSAI() ' If you're using native BrightScript: adapter = harmonicinc_vos_roku_rafx_ssai_RAFX_SSAI()Provide the stream URL to the adapter
result = adapter.getStreamInfo(m.top.video.content.url)(Optional) Provide the option object.
initRequest
Whether to send a request first to the session init API to initialise a session.
By default, this is
trueif the options object is not provided. You may setinitRequesttofalseso that the adapter will obtain the manifest directly.Note
By setting the
initRequesttotrue, you may omit thesessidquery param in the URL provided to the adapter, and let the SSAI service generate a session ID for you.podRetentionSec
How long to cache the ad metadata in seconds.
By default, this will be 7200 (2 hours). You may set
podRetentionSecto other values.pingIntervalSec
The interval for metadata polling in seconds.
By default, this will be 4 seconds. You may set
pingIntervalSecto other values to control how frequently the adapter checks for new ad metadata.Example usage of options
options = { initRequest: false, podRetentionSec: 3600, pingIntervalSec: 5 } result = adapter.getStreamInfo(m.top.video.content.url, options)Check if
result.ssaiis true. If not, the stream is not compatible with the adapterUse the returned stream URL to play the video
m.top.video.content.url = result.streamUrlSee PlayerTask in the example app for reference
The returned URL is different from the original stream URL. If the returned URL is not used, the SSAI and ad beacons may misalign with the video playback, or beacons will not be fired at all.
(Optional) Add event listeners. Available events include pods and errors:
adapter.addEventListener(adapter.AdEvent.PODS, podsCallback) adapter.addEventListener(adapter.AdEvent.ERROR, errorCallback) sub podsCallback(event as object) ' Your code here. Get pods by event.adPods end sub sub errorCallback(errorInfo as object) ' Handle errors: errorInfo.errorType, errorInfo.message, errorInfo.details end subAvailable Error Types:
InitRequestFailed- Session initialization request failedManifestRequestFailed- Manifest request failedMetadataRequestFailed- Ad metadata request failedInvalidResponseFormat- Response format parsing failedParsingError- Metadata parsing errorInvalidStreamUrl- Stream URL construction failedLateBeaconFailed- Late beacon firing failed
Create message port and add it to the adapter.
Note that the adapter currently does not support custom ad beacon firing at the time of writing. The adapter will handle all the tracking beacons by itself.
port = CreateObject("roMessagePort") adapter.enableAds({ player: { sgNode: <your video node>, port: port }, useStitched: true ' required as firing event on client is not supported yet })Observe
positionfield and create a message loop to feed it to the adapterm.top.video.observeFieldScoped("position", port) m.top.video.observeFieldScoped("control", port) m.top.video.observeFieldScoped("state", port) ' Play video m.top.video.control = "play" while true msg = wait(1000, port) if type(msg) = "roSGNodeEvent" and msg.getField() = "control" and msg.getNode() = m.top.video.id and msg.getData() = "stop" or m.top.video = invalid exit while end if curAd = adapter.onMessage(msg) if curAd = invalid m.top.video.setFocus(true) end if if "roSGNodeEvent" = type(msg) and "state" = msg.getField() and "finished" = msg.getData() and msg.getNode() = m.top.video.id exit while end if end while m.top.video.unobserveFieldScoped("position") m.top.video.unobserveFieldScoped("control") m.top.video.unobserveFieldScoped("state")
Development
Example app tryout
Example app is included in /demo for reference. Demo depends on local SDK instead of the one on npm.
ropm packager is required. Install it globally by
npm i ropm -gYou'll need to install the dependencies of the SDK first by
cd lib
npm i
ropm iMove on to the demo app, do the same by
cd ../demo
npm i
ropm iBuild the app
Since the manifest URL is hardcoded, you'll need to replace it prior to building the app.
In demo/components/Tasks/PlayerTask.bs line 3, you should have the following:
const url = ""Replace it with the manifest URL, for example
const url = "https://www.example.com/master.mpd"Optional
To force the adapter to obtain the manifest directly instead of using the session init API, set the following in lines 4-6:
const options = { initRequest: false }
Then locate to the demo app root directory i.e. demo/. Run the following:
npm run packageThe Roku app package will be saved as /demo/out/demo.zip. Upload this zip file in Roku debug web UI to install it.
Develop on Roku w/ live reload
Edit demo/bsconfig.json. Fill in the host and password with the Roku device's IP and developer mode password respectively
Then run the following
npm run watchAppendix
How the Playback URL and Beaconing URL are Obtained by the Library
[!NOTE]
Applicable wheninitRequestin the options provided istrue(default is true).
The library sends a GET request to the manifest endpoint with the query param "initSession=true". For e.g., a request is sent to:
https://my-host/variant/v1/hls/index.m3u8?initSession=trueThe ad insertion service (PMM) responds with the URLs. For e.g.,
{ "manifestUrl": "./index.m3u8?sessid=a700d638-a4e8-49cd-b288-6809bd35a3ed&vosad_inst_id=pmm-0", "trackingUrl": "./metadata?sessid=a700d638-a4e8-49cd-b288-6809bd35a3ed&vosad_inst_id=pmm-0" }The library constructs the URLs by combining the host and base path in the original URL and the relative URLs obtained. For e.g.,
Manifest URL: https://my-host/variant/v1/hls/index.m3u8?sessid=a700d638-a4e8-49cd-b288-6809bd35a3ed&vosad_inst_id=pmm-0 Metadata URL: https://my-host/variant/v1/hls/metadata?sessid=a700d638-a4e8-49cd-b288-6809bd35a3ed&vosad_inst_id=pmm-0
[!NOTE]
The resulting manifest URL above can be obtained in the returned result'sstreamUrlwhen callinggetStreamInfo.
