# MediaMelon Roku SDK Integration Document

**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:** [Request Information](#step-4-request-information)

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

**Step 6:** [Custom Events](#step-6-custom-events)

[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 SDK](https://sdks.mediamelon.com/roku/qoe/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="mmRafEvent" type="assocarray" 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="requestInfo" type="assocarray" 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>
```

#### 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 %}

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

#### 3.3. Set Configuration Details:

```raku
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"
  disableManifestFetch: true
  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" %}

* `disableManifestFetch`: If your workflow restricts the manifest to be accessible from both the player and SDK simultaneously, you can disable manifest fetch. This is an optional step.
* `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:

```raku
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:

```raku
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:

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

#### 3.7. Set Custom Metadata:

```raku
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 `1.25 seconds` in the SDK.&#x20;

```raku
m.MM.setField("seekThreshold", 2)
```

#### 3.9. Set is Video Live:

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

```raku
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 the view ends.
{% endhint %}

* **Start View:**

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

* **End View:**

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

#### 3.11. Run the SDK:

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

### Step 4: Request Information

Report `failed` or `cancelled` requests for the following request types:

* PIR
* MANIFEST
* AUDIO\_CHUNK
* VIDEO\_CHUNK
* DRM
* SUBTITLE

```raku
requestInfo = { 
    requestStatus: <request_status>,    'string (This should be "failed" or "cancelled")
    requestType: <request_type>,        'string (This can be pir, manifest, audio_chunk, video_chunk, drm, subtitle)
    id: "ID",
    error: "ERROR",
    text: "TEXT",
    hostname: "HOSTNAME",
    url: "URL"
}

m.MM.setField("requestInfo", requestInfo)
```

### Step 5: Error Handling

By default, the SDK listens to the video node for errors. To report custom errors, set `enableCustomErrorReporting` flag to `true` in `MMConfig` 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 %}

#### 5.1. Video Error Reporting:

```raku
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 %}

#### 5.2. Ad Error Reporting:

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

#### Step 6: Custom Events:

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[^1]

* Added support for reporting a new field encoding service via `customConfig`.
* Introduced custom event reporting through `customEvent` interface.
* Added FPS reporting in the Rendition event.
* Fixed the `NA` Asset Name issue.

</details>

***

<details>

<summary>Previous Releases</summary>

#### v2.8.0[^2]

* Added `CDN_CHANGE` event functionality.
* Added Seek Duration calculation internally.
* Added Audio and Video Codecs in Rendition Event.

#### v2.7.2[^3]

* Cleaned up the content change handler

#### v2.7.1[^4]

* Fixed a bug in HTTP port handling in the case of upnext.

#### v2.7.0[^5]

* Updated network call handling to avoid waiting after the HTTP call.
* Updated Device Resolution string.

#### v2.6.5[^6] &#x20;

* Device & Network Information fixes
* Fixed Player Resolution
* Preload field addition
* App Session Id field addition
* Fix to consider Exit in Buffering

</details>

[^1]: **Release Date:** Mar 30, 2026

    **Performance Report:** [here](https://docs.mediamelon.com/mediamelon-sdk-performance-metrics/roku/roku-sdk-performance-metrics)

[^2]: **Release Date:** Feb 06, 2026

    **Performance Report:** [here](https://docs.mediamelon.com/mediamelon-sdk-performance-metrics/roku/roku-sdk-performance-metrics)

[^3]: Release Date: Jan 23, 2026

[^4]: **Release Date:** Jan 6, 2026

    **Performance Report:** [here](https://docs.mediamelon.com/mediamelon-sdk-performance-metrics/roku/roku-sdk-performance-metrics)

[^5]: **Release Date:** Dec 22, 2025

[^6]: **Release Date:** Dec 12, 2025
