Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
1 change: 1 addition & 0 deletions ads/api/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ The [OptiView Ads SDK](../player-integration/optiview-ads-sdk/index.mdx) ships a
- [Android API reference](pathname:///ads/v2/api-reference/android/) for the `com.dolby.optiview:ads-sdk` artifacts (Kotlin).
- [iOS and tvOS API reference](pathname:///ads/v2/api-reference/ios/) for the `OptiViewAdsSDK` Swift packages (DocC, one module per package).
- [React Native API reference](pathname:///ads/v2/api-reference/react-native/) for the `@dolby-optiview/ads-sdk-react-native` package.
- [Roku API reference](pathname:///ads/v2/api-reference/roku/) for the `OptiViewAds` SceneGraph component in the `@dolby-optiview/ads-sdk-roku` package.
2 changes: 1 addition & 1 deletion ads/player-integration/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ To play the ad breaks you schedule with OptiView Ads, your application needs a p

## OptiView Ads SDK (recommended)

The [OptiView Ads SDK](./optiview-ads-sdk/index.mdx) lets you **bring your own player**. It handles the Break Manifest logic and ad tracking/analytics for you, while your application keeps full control over content playback. It is available for Web, Android, iOS, and React Native, with ready-made adapters for popular players.
The [OptiView Ads SDK](./optiview-ads-sdk/index.mdx) lets you **bring your own player**. It handles the Break Manifest logic and ad tracking/analytics for you, while your application keeps full control over content playback. It is available for Web, Android, iOS, React Native, and Roku, with ready-made adapters for popular players.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NIT] Platform-guide lists in two other pages still omit Roku

The same list update is still missing in ads/how-to-guides/workflow-integration.md:36 ("see the platform guides for Web, Android, iOS, and React Native") and ads/getting-started/index.mdx:85 ("Follow the platform guide for Web, Android, iOS, or React Native"), so the new Roku guide is not discoverable from the getting-started or workflow entry points.

Fix: add [Roku](../player-integration/optiview-ads-sdk/roku.mdx) to the workflow guide's list (relative .mdx links, like its neighbours) and [Roku](/ads/player-integration/optiview-ads-sdk/roku) to the getting-started list (absolute paths, like its neighbours).


This is the recommended path for any new integration.

Expand Down
2 changes: 1 addition & 1 deletion ads/player-integration/optiview-ads-sdk/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ The OptiView Ads SDK is the recommended way to integrate OptiView Ads into your
- **Ad playback:** the SDK renders the scheduled ads, including the different [break layouts](../../concepts/breaks.mdx#layouts), on top of your content player.
- **Ad tracking and analytics:** the SDK reports the ad impressions and tracking events for the ads it plays.

The SDK is available for [Web](./web.mdx), [Android](./android.mdx), [iOS](./ios.mdx), and [React Native](./react-native.mdx).
The SDK is available for [Web](./web.mdx), [Android](./android.mdx), [iOS](./ios.mdx), [React Native](./react-native.mdx), and [Roku](./roku.mdx).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NIT] SDK overview generalisations (adapter, container, customAssetKey) no longer hold for Roku

With Roku added to this list, the rest of the page still speaks for every platform: line 11 "renders the scheduled ads, including the different break layouts, on top of your content player" (on Roku the ads replace content in-stream and there are no layouts), line 18 "All player interaction goes through a small player adapter interface … ready-made adapters for popular players on each platform" (Roku binds a Video node; roku.mdx:8 says "Instead of a player adapter"), lines 31–32 player / container Required, and line 44 customAssetKey in the session configuration (Roku's startSession takes contentUrl / manifestUrl and reads the key from the manifest — roku/api/OptiViewAds.json startConfig at v1.2.1). A one-sentence qualifier here keeps the page accurate without rewriting it:

Suggested change
The SDK is available for [Web](./web.mdx), [Android](./android.mdx), [iOS](./ios.mdx), [React Native](./react-native.mdx), and [Roku](./roku.mdx).
The SDK is available for [Web](./web.mdx), [Android](./android.mdx), [iOS](./ios.mdx), [React Native](./react-native.mdx), and [Roku](./roku.mdx). The adapter and configuration model below applies to Web, Android, iOS, and React Native; on Roku the SDK is a SceneGraph component that binds your `Video` node directly and reads the Google configuration from the Break Manifest — see the [Roku page](./roku.mdx).


## How the SDK works with your player

Expand Down
103 changes: 103 additions & 0 deletions ads/player-integration/optiview-ads-sdk/roku.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
sidebar_position: 6
sidebar_label: Roku
---

# OptiView Ads SDK on Roku

On Roku, the OptiView Ads SDK is a SceneGraph component, `OptiViewAds`, for clear live HLS streams. Instead of a player adapter, it works with one `Video` node that your channel owns and never changes that node's source at an ad boundary:

- **Client-side stitching (SGAI):** the component replaces content segments with the Google Ad Manager pod at the break times in the channel's [Break Manifest](../../concepts/break-manifest.mdx). The player plays one continuous stream.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[SHOULD-FIX] Four other authored pages still say Roku cannot run SGAI / a client-side SDK

This bullet documents client-side Google Ad Manager pod stitching (SGAI) on Roku, and the SDK 1.2.1 changelog makes the Roku SDK non-experimental — but four sentences elsewhere in ads/ still tell readers the opposite, and none of those files is in this PR:

Scenario: a Roku developer reading the Google integration or workflow guide is steered to Google DAI only, then lands on this page, which says the SDK stitches GAM pods client-side on Roku. This was flagged on e09a621 too; commits ccad219/e8980bb fixed the API-reference page, the sidebar and two platform lists, but not these sentences.

Fix: drop Roku from the "cannot" examples in all four sentences (e.g. "such as older connected TV devices without an OptiView Ads SDK"); optionally add that on Roku the SDK itself follows the Break Manifest's delivery rule and plays the Google DAI stream when SSAI is selected, as line 11 here already says.

- **Server-side insertion (SSAI):** when the Break Manifest's delivery rule for TV devices selects SSAI, the component plays the channel's Google DAI live stream instead.

## Prerequisites

1. Retrieve the channel's Break Manifest URL. See [Retrieving the required values](./index.mdx#retrieving-the-required-values).
2. For [Google Pod Serving](../../integrations/google/pod-serving.mdx), configure the Google Ad Manager `networkCode` and `customAssetKey` on the channel. The Roku SDK reads them from the Break Manifest.
3. The content must be clear (not DRM-protected) live HLS with `EXT-X-PROGRAM-DATE-TIME` tags, in MPEG-TS or CMAF, with up to eight renditions.
Comment on lines +16 to +17

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NIT] Prerequisites: network code is organization-level; PDT/format/rendition limits are SGAI-only

Two precision issues in the prerequisites:

  • Line 16 says to configure the networkCode "on the channel". Per ads/integrations/google/index.mdx:19-23 the network code is organization-level (set up by the account team); only the custom asset key is configured on the channel (pod-serving.mdx:52-54), after which the Break Manifest carries both — which is what the Roku SDK reads (roku/sdk/source/OptiViewAds/ManifestPolicy.brs:9 at v1.2.1).
  • Line 17 states the EXT-X-PROGRAM-DATE-TIME / MPEG-TS-or-CMAF / eight-rendition requirements unconditionally, but they are stitching (SGAI) requirements: the generated Roku reference's capabilities say sourceProgramDateTimeRequired — "SGAI needs EXT-X-PROGRAM-DATE-TIME on the content" and maxRenditions: 8 — "Maximum number of renditions stitched together" (roku/index.html:226,234); when the first manifest selects SSAI the SDK discards pending stitching failures and plays the Google DAI stream (SessionSsai.brs:122-137 at v1.2.1). The clear-content (no DRM) requirement is unqualified in the capabilities, so it stays general.
Suggested change
2. For [Google Pod Serving](../../integrations/google/pod-serving.mdx), configure the Google Ad Manager `networkCode` and `customAssetKey` on the channel. The Roku SDK reads them from the Break Manifest.
3. The content must be clear (not DRM-protected) live HLS with `EXT-X-PROGRAM-DATE-TIME` tags, in MPEG-TS or CMAF, with up to eight renditions.
2. For [Google Pod Serving](../../integrations/google/pod-serving.mdx), enable it on the channel by configuring the channel's `customAssetKey`. The Roku SDK reads the Google Ad Manager `networkCode` and `customAssetKey` from the Break Manifest.
3. The content must be clear (not DRM-protected) live HLS. For client-side stitching (SGAI) it also needs `EXT-X-PROGRAM-DATE-TIME` tags, MPEG-TS or CMAF segments, and at most eight renditions.


## Installation

The SDK is published on npm as `@dolby-optiview/ads-sdk-roku`. Install it with [ropm](https://github.com/rokucommunity/ropm), the Roku package manager, and list it in `ropm.noprefix` so the component keeps the name `OptiViewAds`:

```bash
npm install ropm --save-dev
npx ropm install @dolby-optiview/ads-sdk-roku
```

```json
{
"dependencies": { "@dolby-optiview/ads-sdk-roku": "<version>" },
"ropm": { "noprefix": ["@dolby-optiview/ads-sdk-roku"] }
}
```

Without `noprefix`, ropm prefixes every component and function of the package; create the node as `dolbyoptiview_adssdkroku_OptiViewAds` then. The package includes a Google IMA task component named `IMASDKTask`; if your channel already has a component with that name, install with the prefix.

Without ropm, install the package with npm and copy its `channel/` folder into your channel root:

```bash
npm install @dolby-optiview/ads-sdk-roku
cp -R node_modules/@dolby-optiview/ads-sdk-roku/channel/. <your-channel-root>/
```

The package is a component library, not a stand-alone channel. It adds `components/OptiViewAds/`, the Google IMA task under `components/Player/`, helpers under `source/` and the Break Manifest verification keys under `manifest-keys/`. Declare the Roku libraries it needs in your channel's `manifest`:

```properties
bs_libs_required=googleima3,roku_ads_lib
```

## Integration

Create the component, bind your `Video` node and a node for the Google IMA ad UI, observe the result and event fields, then start a session with the channel's Break Manifest URL:

```brightscript
m.ads = CreateObject("roSGNode", "OptiViewAds")
m.top.AppendChild(m.ads)
m.ads.videoNode = m.top.FindNode("video")
Comment on lines +55 to +57

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[SHOULD-FIX] Integration snippet uses m.video, which is never assigned

The OnAdsOperation handler below (lines 77–78) does m.video.content = content / m.video.control = "play", but this setup snippet only binds m.ads.videoNode = m.top.FindNode("video") and never assigns m.video. Copied as-is into a component with <Video id="video" />, m.video is invalid and the first status = "ready" result throws Dot Operator attempted with invalid BrightScript Component or interface reference instead of starting playback. The SDK's own test app keeps the node in a variable and binds that (roku/test-app/components/SdkTestTheo.brs:41,51 at dolby-ads-sdk v1.2.1).

Suggested change
m.ads = CreateObject("roSGNode", "OptiViewAds")
m.top.AppendChild(m.ads)
m.ads.videoNode = m.top.FindNode("video")
m.video = m.top.FindNode("video")
m.ads = CreateObject("roSGNode", "OptiViewAds")
m.top.AppendChild(m.ads)
m.ads.videoNode = m.video

m.ads.adUiNode = m.top.FindNode("adUi")
m.ads.ObserveField("operationResult", "OnAdsOperation")
m.ads.ObserveField("sdkEvent", "OnAdsEvent")
m.ads.ObserveField("diagnosticEvent", "OnAdsDiagnostic")
m.ads.CallFunc("startSession", {
contentUrl: "https://cdn.example.com/live/master.m3u8"
manifestUrl: "https://us.markers.optiview.dolby.com/manifest/v1/ORG-ID/channels/CHANNEL-ID"
})
```

`startSession` returns an operation ID. When `operationResult` reports `status: "ready"` for it, play **its `playbackUrl`** on your `Video` node; the SDK never sets the source itself:

```brightscript
sub OnAdsOperation(event as Object)
result = event.GetData()
if result.status = "ready"
content = CreateObject("roSGNode", "ContentNode")
content.url = result.playbackUrl
content.streamFormat = "hls"
m.video.content = content
m.video.control = "play"
end if
end sub
```

From this point the SDK polls the [Break Manifest](../../concepts/break-manifest.mdx), inserts the breaks at their scheduled times, and reports the ad events and impressions from Google IMA. To verify the integration, schedule a break through the API or dashboard and confirm that it plays out.

To stop, call `endSession`, stop and detach playback, then call `destroy`.

All fields, functions, start configuration options, events, diagnostics and capabilities are documented in the [Roku API reference](pathname:///ads/v2/api-reference/roku/).

## Supported players

### Roku Video node

The SDK binds the channel's own `Video` node, as shown above.

**Limitations:**

- Breaks need the stream's `EXT-X-PROGRAM-DATE-TIME`; a break that starts between segment boundaries starts at the nearest boundary.
- DRM, VOD, low-latency HLS parts, pre-rolls, post-rolls, pause ads and VAST are not supported.
- A break that fails after its ads were published ends playback; start a new session to continue.

### OptiView Player (THEOplayer) for Roku

THEOplayer owns its `Video` node. Bind that node (`player.callFunc("getVideoNode")`) to `videoNode`, then load the `playbackUrl` through THEOplayer's own source API instead of setting the `Video` content directly.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</a> <button class="navigation-controls--btn navigation-controls--btn_toc ui-kit_mobile-only" id="toc-toggle" type="button">Toggle table of contents
</button>
<div class="navigation-controls--break ui-kit_mobile-only"></div>
<div class="library-version" id="library-version">1.0.0
<div class="library-version" id="library-version">1.2.1
</div>
<div class="navigation-controls">
<ul class="filter-section filter-section_loading" id="filter-section" aria-label="Target filter">
Expand Down
Loading
Loading