OptiView Ads SDK on Roku
On Roku, the OptiView Ads SDK is a SceneGraph component that works with an application-owned Video node. It supports Google Ad Manager ads in clear live HLS streams through server-guided ad insertion (SGAI) or Google DAI live streams through server-side ad insertion (SSAI).
Unlike the other platform integrations, Roku does not use a player adapter. Your application binds its Video node to the SDK and loads the playback URL returned by the session.
Prerequisites
- Retrieve the channel's Break Manifest URL. See Retrieving the required values. Network Break Manifests must carry a valid detached signature.
- Provide a clear live HLS content URL. SGAI requires
EXT-X-PROGRAM-DATE-TIMEtags and compatible content and ad renditions. - Obtain the signed Roku SDK component-library package for your SDK version.
Roku supports live Google Ad Manager workflows. VOD, standalone VAST tags, static assets, DRM, low-latency HLS parts, and nonlinear layouts are not supported. In SSAI mode, the SDK uses Google DAI full-service live HLS and does not render client-side manifest breaks. See the Roku API reference for the supported capabilities.
Installation
Copy the signed SDK package into your channel as components/OptiViewAds.pkg. Add the required libraries to your channel's manifest:
bs_libs_required=roku_ads_lib,googleima3
Load the package with a ComponentLibrary node in your scene:
<ComponentLibrary id="OptiViewAds" uri="pkg:/components/OptiViewAds.pkg" />
Wait until the library's loadStatus is ready before creating OptiViewAds:OptiViewAds. Handle a failed library load before starting a session.
Integration
Expose the SDK listener as an interface function on your application component, and provide the content player and a group for Google IMA's ad UI:
<interface>
<function name="onAdsOperation" />
</interface>
<children>
<Video id="video" width="1920" height="1080" />
<Group id="adUi" />
</children>
After the library is ready, call startAds from your component's BrightScript code. Register listeners before calling startSession, because validation failures can be reported immediately:
sub startAds()
m.video = m.top.findNode("video")
m.ads = createObject("roSGNode", "OptiViewAds:OptiViewAds")
m.top.appendChild(m.ads)
m.ads.videoNode = m.video
m.ads.adUiNode = m.top.findNode("adUi")
m.ads.callFunc("addEventListener", m.ads.events.operationresult, m.top, "onAdsOperation")
m.startOperation = m.ads.callFunc("startSession", {
contentUrl: "https://content.example.com/live/master.m3u8"
manifestUrl: "https://us.markers.optiview.dolby.com/manifest/v1/ORG-ID/channels/CHANNEL-ID"
})
end sub
sub onAdsOperation(result as object)
if result.operation <> "startSession" or result.operationId <> m.startOperation then return
if result.status = "error"
print "OptiView Ads session failed: "; result.reason
return
end if
if result.status <> "ready" then return
content = createObject("roSGNode", "ContentNode")
content.url = result.playbackUrl
content.streamFormat = "hls"
content.live = true
content.playStart = -1
m.video.content = content
m.video.control = "play"
end sub
startSession returns an operation ID, not a playback URL. The matching operationresult event with status ready carries playbackUrl and the selected deliveryMode. Always load that URL rather than the original content URL. The SDK never sets the Video node's source itself.
The channel's Break Manifest selects SGAI or SSAI for the device. In SGAI, playbackUrl is the SDK's local proxy URL. In SSAI, it is the Google DAI stream URL.
Using OptiView Player
If your channel plays content with the OptiView Player Roku SDK, register the OptiViewAds:OptiViewAdsSDKIntegration component with the player. The player's ads API then dispatches the SDK's ad break and ad events and keeps player.ads.playing, currentAdBreak and currentAds up to date, so code that already listens on player.ads needs no second event source. The SDK keeps emitting its own events as well.
Register the integration once per player, before loading the source:
m.integration = createObject("roSGNode", "OptiViewAds:OptiViewAdsSDKIntegration")
m.integration.adsSdk = m.ads
m.player.ads.callFunc("registerServerSideIntegration", m.integration.integrationKind, m.integration)
On the ready result of startSession, load playbackUrl into the player instead of the Video node, and reference the integration in the source's ssai description:
m.player.source = {
sources: [{
src: result.playbackUrl
type: "application/x-mpegurl"
ssai: { integration: m.integration.integrationKind }
}]
live: true
}
The player only starts the integration for sources with this ssai description, and the integration accepts the source only while the SDK session is active. Do not call the integration's functions yourself; the player invokes them. Destroying the player with player.callFunc("destroy") tears the integration down; destroy the OptiViewAds node afterwards. See the Roku API reference for details.
Events and configuration
Subscribe to ad and diagnostic events with the same addEventListener pattern. Each listener owner must expose its callback as an interface function. Remove a listener with removeEventListener, using the same event type, owner, and function name.
The SDK also exposes session configuration, ad targeting updates, status snapshots, and capability information. See the Roku API reference for the full interface.
Ending a session
End the session, stop and detach playback, then destroy the SDK component:
m.ads.callFunc("endSession")
m.video.control = "stop"
m.video.content = invalid
m.ads.callFunc("destroy")
While playback is still attached, endSession reports draining and keeps the published stream available. destroy refuses to release the component while the Video node still uses the SDK's playback URL.