# MediaMelon iOS Custom SDK Integration Document

**Step 1:** [Add MediaMelon SDK](#step-1-add-mediamelon-smartstreaming-sdk-hardbreak)

**Step 2:** [Register and Initialize MediaMelon SDK](#step-2-register-and-initialize-mediamelon-sdk)

**Step 3:** [Additional Custom Metadata](#step-3-additional-custom-metadata)

**Step 4:** [Network and Stream Information](#step-4-network-and-stream-information)

**Step 5:** [Chunk/Segment Information](#step-5-chunk-segment-information)

**Step 6:** [Player Events](#step-6-player-events)

**Step 7:** [Fallback & Request Status](#step-7-fallback-and-request-status)

**Step 8:** [Ad Data & Ad Events](#step-8-a-d-data-and-ad-events)

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

[Release Notes](#release-notes)

### **Step 1: Add** MediaMelon SDK <a href="#step-1-add-mediamelon-smartstreaming-sdk-hardbreak" id="step-1-add-mediamelon-smartstreaming-sdk-hardbreak"></a>

* **SPM:**

```swift
.package(
      url: "https://github.com/MediamelonSDK/mm-ios-qoe-sdk",
      .upToNextMajor(from: "2.16.0")
 ),
```

### **Step 2: Register and Initialize** MediaMelon SDK <a href="#step-2-register-and-initialize-mediamelon-sdk" id="step-2-register-and-initialize-mediamelon-sdk"></a>

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

#### Step 2.1: Instantiate and Set SDK Registration Information:

```swift
let mmCustomAdapter = MMCustomAdapter.shared

let registrationInfo = MMRegistrationInformation(customerID: "CUSTOMER_ID", playerName: "PLAYER_NAME")
registrationInfo.setDomain("DOMAIN_NAME")
registrationInfo.setSubscriberInformation(subscriberID: "SUBSCRIBER", subscriberType: "SUBSCRIBER_TYPE", subscriberTag: "SUBSCRIBER_TAG", hashSubscriberID: false)
registrationInfo.setPlayerInformation(brand: "PLAYER_BRAND", model: "PLAYER_MODEL", version: "PLAYER_VERSION")
registrationInfo.setBasePlayerInformation(basePlayerName: "BASE_PLAYER_NAME", basePlayerVersion: "BASE_PLAYER_VERSION")
```

{% hint style="info" %}
`hashSubscriberID`: Set it to `true` to hash the subscriber ID, and to `false` to process the subscriber ID without hashing.
{% endhint %}

#### Step 2.3: Set Device Information:

```swift
let deviceInfo = MMDeviceInformation()
deviceInfo.setDeviceTpe(type: "DEVICE_TYPE")
deviceInfo.setBrandName(brandName: "BRAND_NAME")    // Device Brand or Manufacturer
deviceInfo.setDeviceModel(deviceModel: "DEVICE_MODEL")
deviceInfo.setOSName(osName: "OS_NAME")
deviceInfo.setOSVersion(osVersion: "OS_VERSION")
deviceInfo.setTelecomOperator(telecomOperator: "TELECOM_OPERATOR")
deviceInfo.setScreenResolution(width: <screen_width>, height: <screen_height>)  //Integer Value
```

#### Step 2.4: Report Application Information:

```swift
mmCustomAdapter.reportAppData(appName: "APP_NAME", appVersion: "APP_VERSION")
```

#### Step 2.5: Report Application Session ID:

```swift
mmCustomAdapter.reportAppSessionID(appSessionId: "APP_SESSION_ID")
```

#### Step 2.6: Report Experiment Name & Sub Property ID:

```swift
mmCustomAdapter.reportExperimentName(experimentName: "EXPERIMENT_NAME")
mmCustomAdapter.reportSubPropertyID(subPropertyId: "SUBPROPERTY_ID")
```

#### Step 2.7: Set Content Metadata:

```swift
let assetInfo = MMAssetInformation(assetURL: "STREAM_URL", assetID: "ASSET_ID", assetName: "ASSET_NAME", videoId: "VIDEO_ID")
assetInfo.setEpisodeNumber("EPISODE_NUMBER")
assetInfo.setContentType("CONTENT_TYPE")
assetInfo.setSeriesTitle("SERIES_TITLE")
assetInfo.setGenre("GENRE")
assetInfo.setSeason("SEASON")
assetInfo.setDrmProtection("DRM_PROTECTION")
assetInfo.addCustomKVP("CUSTOM_1", "VALUE_1")
assetInfo.addCustomKVP("CUSTOM_2", "VALUE_2")

mmCustomAdapter.reportViewSessionID(viewSessionId: "VIEW_SESSION_ID")
```

#### Step 2.8: Initialize Session with Content Metadata:

```swift
mmCustomAdapter.initializeAssetForPlayer( assetInfo: assetInfo, 
                                         registrationInfo: registrationInfo, 
                                         deviceInfo: deviceInfo)
mmCustomAdapter.reportPreload(<boolean>)
mmCustomAdapter.reportUserInitiatedPlayback()
```

{% hint style="info" %}
**Preload:** Report the preload attribute after `initializeAssetForPlayer` and before `reportUserInitiatedPlayback`. The preload value is reset inside `initializeAssetForPlayer`, so reporting it before this method will be ignored. If you report it after `reportUserInitiatedPlayback`, the first event will not contain the preload field.
{% endhint %}

### Step 3: Additional Custom Metadata

Check the custom tags configuration in your [dashboard](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.

```swift
mmCustomAdapter.reportCustomMetadata(key: "CUSTOM_3", value: "VALUE_3")
```

### Step 4: Network and Stream Information

#### Step 4.1: Report Network Information:

```swift
mmCustomAdapter.reportNetworkInfo(cdn: "CDN", 
                                  asn: <asn>,                     // Integer Value
                                  hostName: "SOURCE_HOST_NAME", 
                                  networkType: "NETWORK_TYPE",    // Network Connection Type
                                  networkOperator: "NETWORK_OPERATOR")
```

{% hint style="info" %}
Use the `reportNetworkInfo` API to report the CDN along with other network information.\
If additional network information is not available, use `reportCDN` instead.
{% endhint %}

#### Step 4.2: Report CDN Information:

```swift
mmCustomAdapter.reportCDN(cdn: "CDN")
```

#### Step 4.3: Report Stream Information:

```swift
mmCustomAdapter.reportStreamInfo(streamURL: "STREAM_URL", 
                                 streamFormat: "STREAM_FORMAT", 
                                 mediaType: "MEDIA_TYPE", 
                                 sourceType: "SOURCE_TYPE")
```

#### Step 4.4: Report Video Presentation Information:

```swift
mmCustomAdapter.reportPresentationInfo(isLive: <is_live>, videoDurationInMS: <video_duration>)
```

{% hint style="info" %}

* `is_live`: Set to `true` for live video stream and to `false` for the VOD stream.
* `video_duration`: Video duration in milliseconds.
  {% endhint %}

#### Step 4.5: Report Track Information:

Call this API with initial values and every time there is a change in the track info. Call this API when the user enables/disables subtitles or when the user changes the audio track.

```swift
mmCustomAdapter.reportMediaTrackInfo(isSubtitleActive: <is_subtitle_active>, subtitleTrack: "SUBTITLE_TRACK", audioTrack: "AUDIO_TRACK", isVDSActive: <is_vds_active>);
```

{% hint style="info" %}
`is_subtitle_active`: Set it to `true` if the subtitles are active; otherwise, set it to `false`.

`is_vds_active`: Set it to `true` if the type of audio is Virtual Dialogue Sound, otherwise, set it to `false`.
{% endhint %}

#### Step 4.6: Report Rendition:

At the start of the video, create a ReditionInfo object, assign initial rendition values to the object, and report it to the SDK. For any subsequent rendition change, update only the fields that changed in the same RenditionInfo object. Leave the unchanged fields as-is, and report the updated object to the SDK.

```swift
var renditionInfo = MMRenditionInformation()

renditionInfo.bitrate = <bitrate>            //Integr Value in bps
renditionInfo.width = <width>                //Integer Value
renditionInfo.height = <height>              //Integer Value
renditionInfo.frameRate = <frame_rate>       //Double Value in fps
renditionInfo.aCodec = "AUDIO_CODEC"
renditionInfo.vCodec = "VIDEO_CODEC"

mmCustomAdapter.reportRendition(renditionInfo: renditionInfo)
```

#### Step 4.7: Update DRM Type:

```swift
mmCustomAdapter.updateDrmType("NEW_DRM_TYPE");
```

#### Step 4.8: Report Encoding Service:

```swift
mmCustomAdapter.reportEncodingService("ENCODING_SERVICE");
```

### Step 5: Chunk/Segment Information

#### Step 5.1: Report Download Rate:

Report the latest chunk download rate using this method. Trigger this method for every chunk.

```swift
mmCustomAdapter.reportDownloadRate(downloadRate: <downloadRate>)  //Integer Value in bps
```

### Step 6: Player Events

#### Step 6.1: Report Player State:

```swift
mmCustomAdapter.reportPlayerState(playerState: .PLAYING)

Enum: MMPlayerState
- PLAYING
- PAUSED
- STOPPED
```

#### Step 6.2: Report Buffering:

```swift
mmCustomAdapter.reportBufferingStarted()
mmCustomAdapter.reportBufferingCompleted()
```

#### Step 6.3: Report Seek:

```swift
mmCustomAdapter.reportPlayerSeekStarted() 
mmCustomAdapter.reportPlayerSeekCompleted(seekEndPositionInMS: <seek_end_position>) //Integer Value in Milli Seconds
```

#### Step 6.4: Report Error:

```swift
mmCustomAdapter.reportError(errorCode: "ERROR_CODE",
                            errorMessage: "ERROR_MESSAGE",
                            errorDetails: "ERROR_DETAILS")
```

#### Step 6.5: Report Warning:

```swift
mmCustomAdapter.reportWarning(warningCode: "WARNING_CODE",
                              warningMessage: "WARNING_MESSAGE",
                              warningDetails: "WARNING_DETAILS")
```

#### Step 6.5: Report Playback Position:

Call this every 0.5 sec or 1 sec to report the playback position from the player

```swift
mmCustomAdapter.reportPlaybackPosition(currentPlayerPosInMS: <playback_position>) //Integer Value in Milli Seconds
```

#### Step 6.6: Report Player Resolution:

```swift
mmCustomAdapter.reportPlayerResolution(width: <width>, height: <height>)
```

### Step 7: Fallback & Request Status

#### Step 7.1: Report Fallback Event:

```swift
mmCustomAdapter.reportFallbackEvent(fallbackManifestURL: "NEW_STREAM_URL", description: "DESCRIPTION")
```

#### Step 7.2: Report Request Status:

Report `FAILED` or `CANCELLED` requests for the following request types:

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

```swift
var requestInfo : [String: Any] = [
    "id": "ID",
    "url": "URL",
    "error": "ERROR",
    "text": "TEXT",
    "hostname": "HOSTNAME",
    "url": "URL",
    ...
]

mmCustomAdapter.reportRequestStatus(status: .CANCELLED, type: "REQUEST_TYPE", requestInfo: requestInfo)

Enum: RequestStatus
- FAILED
- CANCELLED
```

### Step 8: Ad Data & Ad Events

#### Step 8.1: Report Ad Break Start & End:

```swift
mmCustomAdapter.reportAdBreakStart()
mmCustomAdapter.reportAdBreakEnd()
```

#### Step 8.2: Report Ad Data, Ad Start & End:

```swift
let adInfo = MMAdInfo()
adInfo.adTitle = "AD_TITLE"
adInfo.adId = "AD_ID"
adInfo.adCreativeId = "AD_CREATIVE_ID"
adInfo.adCreativeType = "AD_CREATIVE_TYPE"
adInfo.adClient = "AD_CLIENT"
adInfo.adPosition = "AD_POSITION"                    //pre, mid, post
adInfo.adServer = "AD_SERVER"
adInfo.adResolution = "AD_RESOLUTION"
adInfo.adUrl = "AD_URL"
adInfo.adDuration = <ad_duration>                    //Integer Value in Milli Seconds
adInfo.adPodIndex = <pod_index>                      //Integer Value
adInfo.adPositionInPod = <ad_position_in_pod>        //Integer Value
adInfo.adPodLendth = <pod_length>                    //Integer Value
adInfo.isBumper = <is_bumper>                        //Boolean Value

mmCustomAdapter.reportAdStart(adInfo: adInfo)
mmCustomAdapter.reportAdEnd()
```

<details>

<summary>Ad Info Fields &#x26; Description</summary>

<table data-header-hidden><thead><tr><th width="197.25390625">Field</th><th width="114.51953125">Data Type</th><th>Description</th></tr></thead><tbody><tr><td>adInfo.adTitle</td><td>String</td><td>The title or name of the ad, usually provided in the VAST metadata or by the ad server.</td></tr><tr><td>adInfo.adId</td><td>String</td><td>A unique identifier for the ad creative, often defined by the ad server or DSP.</td></tr><tr><td>adInfo.adCreativeId</td><td>String</td><td>The creative ID associated with the specific ad asset (video, image, etc.). Helps in tracking and reporting creative-level performance.</td></tr><tr><td>adInfo.adCreativeType</td><td>String</td><td>The format or type of the ad creative. For example, video/mp4, image/jpeg, etc., or linear, non-linear.</td></tr><tr><td>adInfo.adClient</td><td>String</td><td>The SDK or client library responsible for requesting and playing the ad. Example: Google IMA, Freewheel, SpotX.</td></tr><tr><td>adInfo.adPosition</td><td>String</td><td>The timing of the ad in relation to the main content: "pre" (before), "mid" (during), or "post" (after).</td></tr><tr><td>adInfo.adServer</td><td>String</td><td>The ad server or source that delivered the ad. Example: Google Ad Manager, Freewheel, etc.</td></tr><tr><td>adInfo.adResolution</td><td>String</td><td>The resolution of the ad video (e.g., 1920x1080), useful for reporting and quality monitoring.</td></tr><tr><td>adInfo.adUrl</td><td>String</td><td>The URL from which the ad video is fetched. Typically a media file or stream URL.</td></tr><tr><td>adInfo.adDuration</td><td>Integer</td><td>The total duration of the ad, in milliseconds. Example: 30000 = 30 seconds.</td></tr><tr><td>adInfo.adPodIndex</td><td>Integer</td><td>The index of the ad pod within the stream. Ad pods are groups of ads played together (like a commercial break).</td></tr><tr><td>adInfo.adPositionInPod</td><td>Integer</td><td>The position of the ad within its pod (e.g., 1st ad, 2nd ad in the group).</td></tr><tr><td>adInfo.adPodLendth</td><td>Integer</td><td>The total number of ads in the current pod. Useful for showing “Ad 2 of 5” type of UI.</td></tr><tr><td>adInfo.isBumper</td><td>Boolean</td><td>A boolean (true/false) indicating whether the ad is a bumper ad (short ad, usually &#x3C;6s, played at the start or end of ad breaks).</td></tr></tbody></table>

</details>

#### Step 8.3: Report Ad Buffering:

Use Ad Buffering APIs to report any buffering that occurs during ad playback. For any buffering event, either content buffering or ad buffering should be reported, but not both.

```swift
mmCustomAdapter.reportAdBufferingStrated();
mmCustomAdapter.reportAdBufferingCompleted();
```

### Step 9: 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.

```swift
mmCustomAdapter.reportCustomEvent("EVENT_NAME", "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.16.0[^1]

* Added support for reporting a new field encoding service via `reportEncodingService`.
* Introduced custom event reporting through `reportCustomEvent`.
* Added support for ad buffering events:
  * `reportAdBufferingStarted`
  * `reportAdBufferingCompleted`
* Improved event handling to restrict event reporting after playback has ended.

</details>

***

<details>

<summary>Previous Releases</summary>

#### v2.15.0[^2]

* Added an additional API to report CDN alone.
* Added `CDN_CHANGE` event.
* Added Seek Duration calculation internally.

#### v2.14.2[^3]

* Fixed custom tags are not getting overridden issue in the SDK

#### v2.14.1[^4]

* Added full device information support internally (model, brand, marketing name, OS, OS version)
* Added rendition metrics for upscale and downscale percentage calculations
* Improved bitrate reporting for weighted average bitrate calculation
* Updated internal SDK version format

#### v2.13.0[^5]

* Preload field addition
* App Session ID field addition
* Fix to consider Exit in Buffering

#### v2.12.0[^6]

* Crash fix at Ad Start

</details>

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

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

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

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

[^3]: **Release Date:** Dec 23, 2025

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

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

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

[^6]: **Release Date:** Nov 3, 2025
