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

### 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" />
</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:

```brightscript
MMConfig = {
  customerID: "CUSTOMER_ID"
  subscriberId: "SUBSCRIBER_ID"
  subscriberType: "SUBSCRIBER_TYPE"
  subscriberTag: "SUBSCRIBER_TAG"
  playerName: "Roku"
  disableManifestFetch: false
  domainName: "DOMAIN_NAME"
  appName: "APP_NAME"
  appSdkVersion: "APP_VERSION"
  viewSessionId: "VIEW_SESSION_ID"
  hashSubscriberId: true 'Important
  enableCustomErrorReporting: false '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:

```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"
}
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"
}
```

#### 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
```
