# MediaMelon Roku SDK Integration with IMA

**Step 1:** [Include MediaMelon SmartStreaming SDK](#step-1-include-mediamelon-smartstreaming-sdk)

**Step 2:** [Set up a new MediaMelon Task](#step-2-setup-new-mediamelon-task)

**Step 3:** [MediaMelon Code Integration](#step-3-integrate-mediamelon-code-to-main-application)

**Step 4:** [Error Handling](#step-4-error-handling)

**Step 5:** [Google IMA Ads Integration](#google-ima-a-ds-integration)

**Step 6:** [Custom Events](#google-ima-a-ds-integration-1)

[Release Notes](#release-notes)

### Step 1: Include MediaMelon SmartStreaming SDK <a href="#step-1-include-mediamelon-smartstreaming-sdk" id="step-1-include-mediamelon-smartstreaming-sdk"></a>

To integrate, unzip the MediaMelon Roku library and place the `MMSmartStream` folder in the components directory.

SDK: [MediaMelon Roku IMA SDK](https://sdks.mediamelon.com/roku/ima/2.9.0/MMSmartStream.zip)

### Step 2: Set up a new MediaMelon Task <a href="#step-2-setup-new-mediamelon-task" id="step-2-setup-new-mediamelon-task"></a>

Create a new XML file `MMTask.xml` inside your components folder. This is used to link MediaMelon’s `brs`files into your application.

The `MMTask.xml`file should contain the following:

```xml
<component name="MMTask" extends="Task">
<interface>
    <field id="video" type="node" alwaysNotify="true"/>
    <field id="config" type="assocarray" alwaysNotify="true"/>
    <field id="customConfig" type="assocarray" alwaysNotify="true" /> 
    <field id="contentMetadata" type="assocarray" alwaysNotify="true"/> 
    <field id="customTags" type="assocarray" alwaysNotify="true"/>
    <field id="error" type="assocarray" alwaysNotify="true"/>
    <field id="adError" type="assocarray" alwaysNotify="true"/>
    <field id="view" type="String" alwaysNotify="true"/>
    <field id="exit" type="Boolean" alwaysNotify="true"/>
    <field id="imaads" type="assocarray" alwaysNotify="true"/>
    <field id="isAdImpressionSent" type="Boolean" alwaysNotify="true"/>
    <field id="sdk_version" type="String" alwaysNotify="true"/>
    <field id="seekThreshold" type="Integer" alwaysNotify="true"/>
    <field id="codecs" type="assocarray" alwaysNotify="true" />
    <field id="isVideoLive" type="Boolean" alwaysNotify="true" />
    <field id="customEvent" type="assocarray" alwaysNotify="true" />
</interface>

<script type="text/brightscript" uri="pkg:/Components/MMSmartStream/MMSmartStreamWrapper.brs"/>
<script type="text/brightscript" uri="pkg:/Components/MMSmartStream/MMSmartStreamEngine.brs"/>
<script type="text/brightscript" uri="pkg:/Components/MMSmartStream/MMSmartStreamRokuPlugin.brs"/>
<script type="text/brightscript" uri="pkg:/Components/MMSmartStream/Utilities.brs"/>
</component>
```

### Step 3: MediaMelon Code Integration <a href="#step-3-integrate-mediamelon-code-to-main-application" id="step-3-integrate-mediamelon-code-to-main-application"></a>

#### **3.1.** Add MMTask Child Component:&#x20;

Add the MediaMelon `MMTask` as a child component of the main video scene `custom-playback-channel-master/components/MainScene.xml`

```xml
<component name="MainScene" extends="Scene" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://devtools.web.roku.com/schema/RokuSceneGraph.xsd">
<!-- importing main handler -->
<script type="text/brightscript" uri="pkg:/components/MainScene.brs" />
<children>
    <MMTask id="MM"/>
</children>
```

#### &#x20;3.2. Create MM Task Node:

In the main application, after the video instance has been created, create a MediaMelon Task node, and pass the Video node to it.

{% hint style="info" %}
`CUSTOMER_ID` is your MediaMelon assigned Customer ID. If you do not know your Customer ID, contact MediaMelon at <customer-support@mediamelon.com>.
{% endhint %}

```brightscript
m.MM = m.top.FindNode("MM")
m.MM.setField("video", m.video)
```

#### 3.3. Set Configuration Details:

```javascript
MMConfig = {
  customerID: "CUSTOMER_ID"
  subscriberId: "SUBSCRIBER_ID"
  subscriberType: "SUBSCRIBER_TYPE"
  subscriberTag: "SUBSCRIBER_TAG"
  playerName: "PLAYER_NAME"
  playerVersion: "PLAYER_VERSION"
  basePlayerName: "BASE_PLAYER_NAME"
  basePlayerVersion: "BASE_PLAYER_VERSION"
  domainName: "DOMAIN_NAME"
  appName: "APP_NAME"
  appSdkVersion: "APP_VERSION"
  viewSessionId: "VIEW_SESSION_ID"
  appSessionId: "APP_SESSION_ID"
  hashSubscriberId: false 'Important
  enableCustomErrorReporting: true 'Important
}
m.MM.setField("config", MMConfig)
```

{% hint style="info" %}

* `hashSubscriberId`: Set `true` to hash the subscriberId and to `false` to process the subscriberId without hashing.
* `enableCustomErrorReporting`: If set to `true` SDK will consider only client-reported errors, else if set to `false` SDK will consider errors from the video node. ([Refer Here](#step-4-error-handling))
  {% endhint %}

#### 3.4. Set Content Metadata:

```javascript
contentMetadata = {
  "assetName": "ASSET_NAME",
  "assetId": "ASSET_ID",
  "videoId": "VIDEO_ID",
  "genre": "GENRE",
  "drmProtection": "DRM_PROTECTION",
  "episodeNumber": "EPISODE_NUMBER",
  "season": "SEASON",
  "seriesTitle": "SERIES_TITLE",
  "contentType": "CONTENT_TYPE",
}
m.MM.setField("contentMetadata", contentMetadata)
```

#### 3.5. Set Custom Configuration Details:

```javascript
customConfig = {
  cdn: "CDN"
  experimentName: "EXPERIMENT_NAME"
  subPropertyId: "SUB_PROPERTY_ID"
  streamFormat: "STREAM_FORMAT"
  mediaType: "MEDIA_TYPE"
  drmProtection: "DRM_PROTECTION"
  preload: <boolean>
  encodingService: "ENCODING_SERVICE"
}
m.MM.setField("customConfig", customConfig)
```

#### 3.6. Set Codecs:

```javascript
codecs = {
  video: "VIDEO_CODEC"
  audio: "AUDIO_CODEC"
}
m.MM.setField("codecs", codecs)
```

#### 3.7. Set Custom Metadata:

```javascript
customMetadata = {
  "CUSTOM_KEY_1": "VALUE_1",
  "CUSTOM_KEY_2": "VALUE_2"
}
m.MM.setField("customTags", customMetadata)
```

{% hint style="info" %}
For Custom Metadata, first, provide the mapping in the [SmartSight](https://smartsight3.mediamelon.com/settings) dashboard under the settings section, and send the values to the SDK accordingly.
{% endhint %}

#### 3.8. Set Seek Threshold:

By default seek threshold is set to `2 seconds` in the SDK.&#x20;

```javascript
m.MM.setField("seekThreshold", 5)
```

#### 3.9. Set is Video Live:

Set `isVideoLive` to `true` for live video stream and to `false` for VOD stream

```javascript
m.MM.setField("isVideoLive", true)
```

#### 3.10. Set View:

{% hint style="info" %}
It's important to set the view field  `start` for every new view start, and to `end` when a view ends.
{% endhint %}

* **Start View:**

```javascript
m.MM.setField("exit", false)
m.MM.setField("view", "start")
```

* **End View:**

```javascript
m.MM.setField("view", "end")
m.MM.setField("exit", true)
```

#### 3.11. Run the SDK:

```javascript
m.MM.control = "RUN"
m.player.setFocus(true)
```

### Step 4: Error Handling

By default, the SDK listens to the video node for errors. To report custom errors, set `enableCustomErrorReporting` flag to `true` and report the errors in the following way;

{% hint style="info" %}
Upon setting `enableCustomErrorReporting` flag to `true`, SDK will stop listening to the video node errors. Only custom errors will be reported.
{% endhint %}

#### 4.1. Video Error Reporting:

```javascript
m.MM.error = { 
    errorCode: "ERROR_CODE",
    errorMessage: "ERROR_MESSAGE",
    errorDetails: "ERROR_DETAILS",
    errorSeverity: <error_severity>   'string (This should be "warning" or "fatal")
}
```

{% hint style="info" %}
`error_severity`: Set this to `"warning"` for warnings and set to `"fatal"` for fatal errors.
{% endhint %}

#### 4.2. Ad Error Reporting:

```javascript
m.MM.adError = { 
    errorCode: "ERROR_CODE",
    errorMessage: "ERROR_MESSAGE",
    errorDetails: "ERROR_DETAILS"
}
```

### Step 5: Google IMA Ads Integration <a href="#google-ima-ads-integration" id="google-ima-ads-integration"></a>

This guide demonstrates how to integrate the Mediamelon Roku SDK into a sample video player app with Google Ima Ads. Downloaded the [basic example](https://github.com/googleads/googleads-ima-roku-dai) from GitHub.

#### **5.1. Include MediaMelon Ad Plugin:**

Include `MMImaAdsPlugin.brs`  file into `SDK.xml` as shown below.

```xml
<?xml version = "1.0" encoding = "utf-8" ?>
<component name = "imasdk" extends = "Task">

<script type = "text/brightscript">
    <![CDATA[
        <!-- Your code goes here -->
    ]]>
</script>

<!-- MediaMelon IMA AdPlugin -->
<script type = "text/brightscript" uri="pkg:/Components/MMSmartStream/MMImaAdsPlugin.brs"/>
</component>
```

#### **5.2. Create an IMA Stream Player:**

Call MediaMelon APIs to notify `adBreakStarted` and `adBreakEnded` as shown below.

```javascript
...
sub setupVideoPlayer()
  sdk = m.sdk
  m.player = sdk.createPlayer()
  ...
  m.player.adBreakStarted = Function(adBreakInfo as Object)
    ...
    'MediaMelon API to notify AdBreakStart'
    mmAdBreakStarted(adBreakInfo)
  End Function
  m.player.adBreakEnded = Function(adBreakInfo as Object)
    ...
    'MediaMelon API to notify AdBreakEnd'
    mmAdBreakEnded(adBreakInfo)
  End Function
End Sub
```

#### **5.3. Add Event Listeners and Start the Stream:**

After requesting your stream, add event listeners to track ad progress from the MediaMelon SDK by calling an API `addMediaMelonAdCallbacks` .

```javascript
Sub loadStream()
  sdk = m.sdk
  sdk.initSdk()
  setupVideoPlayer()
  request = sdk.CreateStreamRequest()
  ...
  m.streamManager = Invalid
  While m.streamManager = Invalid
    sleep(50)
    m.streamManager = sdk.getStreamManager()
  End While
  ...
  'MediaMelon Callback Register'
  addMediaMelonAdCallbacks(m.sdk, m.streamManager)
  m.streamManager.start()
End Sub
```

### Step 6: Custom Events <a href="#google-ima-ads-integration" id="google-ima-ads-integration"></a>

The Custom Events API can be used to report events that are not covered by the default MediaMelon-supported events. Custom events must be reported within the SDK activity lifecycle. Events reported before SDK initialization or after session end will be ignored. Please refer to the guidelines and constraints below.

```raku
m.MM.customEvent = {
    eventName: "EVENT_NAME",
    eventValue: "EVENT_VALUE"
}
```

{% hint style="info" %}
**Guidelines & Constraints**

* **Event Name**
  * Maximum length: 35 characters
  * Allowed characters: Alphanumeric and underscore (\_) only
  * Special characters are not supported
  * Recommended format: UPPERCASE with underscores (e.g., DRM\_CHANGE)
* **Event Limits**
  * A maximum of 35 custom events per session is allowed.

Custom events that violate these constraints (invalid event name or exceeding the per-session limit) will be dropped. Event values exceeding 1000 characters will be truncated to 1000 characters.
{% endhint %}

#### Release Notes

<details>

<summary>Current Release</summary>

#### v2.9.0  <sup><sub>**`Mar 20, 2026`**<sub></sup>

* Added new fields: `Encoding Service`, `App Session ID`, and `Preload`
* Added `Seek Duration` metric and improved `Buffering` calculation
* Added `Custom Event` reporting
* Added `CDN Change` event functionality
* Added `FPS` and `Audio/Video Codec` data points in `Rendition` Change events
* Enhanced `Device` and `Network` information reporting
* Corrected `Device` Resolution and `Player` Resolution data
* Improved **network call handling** to eliminate unnecessary waiting after HTTP calls
* Improved `Bitrate` reporting
* Added `errorSeverity` to mark an error, `warning` or `fatal`.

</details>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/roku/roku-with-ima-sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
