# MediaMelon iOS Bitmovin Player SDK Integration Document

**Step 1:** [Add SDK](#step-1-add-sdk)

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

**Step 5:** [Set up Harmonic SSAI Ad Tracking](#step-5-set-up-harmonic-ssai-a-d-tracking)

**Step 6:** [Cleaning up the SDK Session](#step-6-cleaning-up-the-sdk-session)

**Step 7:** [Disable SDK Manifest Fetch](#step-7-disable-sdk-manifest-fetch-optional)

**Step 8:** [Update Content Metadata](#step-8-update-content-metadata)

[Release Notes](#release-notes)

### Step 1: Add SDK

Add the Wrapper file and the framework to the application project

* **Wrapper:** <https://sdks.mediamelon.com/iOS/bitmovin/2.6.2/BitmovinPlayerIntegrationWrapper.swift>
* **Framework:** <https://sdks.mediamelon.com/iOS/bitmovin/2.6.2/MediaMelonHarmonic.xcframework.zip>

#### Step 1.1: Import Frameworks:

```swift
import BitmovinPlayer
import MediaMelonHarmonic
```

### Step 2: Register and Initialize MediaMelon SDK

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

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

```swift
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.2: 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")
```

#### Step 2.3: Report Application Information:

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

#### Step 2.4: Report Application Session ID:

```swift
BitmovinPlayerIntegrationWrapper.shared.reportAppSessionID(appSessionId: "APP_SESSION_ID")
```

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

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

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

```swift
BitmovinPlayerIntegrationWrapper.shared.reportViewSessionID(viewSessionId: "VIEW_SESSION_ID")
BitmovinPlayerIntegrationWrapper.initializeAssetForPlayer(assetInfo: assetInfo, registrationInformation: registrationInfo, player: <player_instance>, isLive: <isLive>)
```

{% hint style="info" %}
**isLive:** Set this to true for a live stream or false for a VOD stream. If isLive is not set here, the SDK will handle it internally.
{% 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
BitmovinPlayerIntegrationWrapper.shared.reportCustomMetadata(key: "CUSTOM_3", value: "VALUE_3")
```

### Step 4: Stream Information

#### Step 4.1: Report CDN Information:

```swift
BitmovinPlayerIntegrationWrapper.shared.reportCDN(cdn: "CDN")
```

#### Step 4.2: Report Stream Information:

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

#### Step 4.3: Update DRM Type:

```swift
BitmovinPlayerIntegrationWrapper.shared.updateDrmType("NEW_DRM_TYPE");
```

### Step 5: Set up Harmonic SSAI Ad Tracking

#### Step 5.1: Initialize Harmonic SSAI Ad Manager:

**HLS** `PMM_URL`: Send the variant URL with the pmm ID.

{% hint style="info" %}
Note: Call `initializeHarmonicSSAIAdManager` only once at the stream start.
{% endhint %}

```swift
BitmovinPlayerIntegrationWrapper.shared.initializeHarmonicSSAIAdManager(streamURL: "PMM_URL")
```

#### Step 5.2: Set up Delegate for Ad Callbacks:

Add the `MMSSAIManagerDelegate` protocol to the required class. To confirm with `MMSSAIManagerDelegate` protocol implement the below method in the class.

```swift
BitmovinPlayerIntegrationWrapper.shared.mmssaiManagerDelegate = self
```

```swift
func notifyMMSSAIAdEvent(eventName: MMHarmonicSSAIAdSate, adInfo: MMHarmonicSSAIAdInfo) {
        if(eventName == .adPlaying){
            print("Ad Playback Time = ", adInfo.getAdCurrentPlybackTime());
        } else {
            print("Current Ad State = ", eventName);
        }
}
```

<details>

<summary><strong>MMHarmonicSSAIAdSate</strong></summary>

* `adImpression`
* `adStarted`
* `adFirstQuartile`
* `adMidpoint`
* `adThirdQuartile`
* `adPlaying`
* `adCompleted`

</details>

<details>

<summary><strong>MMHarmonicSSAIAdInfo Methods</strong></summary>

* `getAdClient()`
* `getAdCurrentPlaybackTime()`
* `getAdDuration()`
* `getAdStartTime()`
* `getAdEndTime()`
* `getAdId()`
* `getAdPosition()`
* `getAdServer()`

</details>

### Step 6: Cleaning up the SDK Session

{% hint style="info" %}
We need to clean up the SDK session once the playback is completed. The SDK internally manages the cleanup for most of the cases. For example, when playback finishes or an error is notified.&#x20;

However, in some error cases, like network reachability issues, the error notification is delayed. Before this error notification is available, the user may trigger another session. Therefore, it is advised to clean up the session once the playback finishes.&#x20;

We recommend a cleanup at the following two places.

* When the view controller hosting the post-roll ad terminates
* When the player is restarted
  {% endhint %}

```swift
BitmovinPlayerIntegrationWrapper.cleanUp()
```

### Step 7: Disable SDK Manifest Fetch (Optional)

If your workflow restricts the manifest to be accessible from both the player and the MediaMelon Player SDK simultaneously, then you can disable the fetch of the manifest as shown below. When calling this method, it should be called before the `initializeAssetForPlayer` method.

```swift
BitmovinPlayerIntegrationWrapper.disableManifestsFetch(disable: true)
```

### Step 8: Update Content Metadata

During linear channel playback, if the content changes and a new session needs to be created for each piece of content, please use the updateAssetInfo method. This method can be used to create a new session while updating the asset information.

```swift
func updateContentMetadata() {
    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")
    
    // Create a new session and update the Asset info
    BitmovinPlayerIntegrationWrapper.updateAssetInfo(assetInfo: assetInfo, player: player)
}
```

### Release Notes:

<details>

<summary><strong>Current Release</strong></summary>

#### v2.6.[^1]2

* Added Ad Buffering tracking.
* Added Seek Duration tracking.

</details>

***

<details>

<summary><strong>Previous Releases</strong></summary>

#### v2.6.1[^2]

* Added Report **CDN API** for clients to provide CDN information to the SDK.
* Added Report **StreamInfo API** for reporting stream format, media type, and source type.
* Enabled the Report **Player Information API** for clients to pass player details to the SDK.
* Updated the **Base Player Information** reporting API.
* Added **App Session ID** API for client-provided session identification.
* Added the **Update DRM Type** API.
* Fixed an issue that caused duplicate rendition events to be reported by the SDK.

#### v2.5.0[^3]

* Fixed a URL dependency issue in the wrapper file
* Removed the number and value from the Streaming Progress and Playback Error events reported to the toolbox endpoint

</details>

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

    **Wrapper:** [here](https://sdks.mediamelon.com/iOS/bitmovin/2.6.2/BitmovinPlayerIntegrationWrapper.swift)

    **Framework:** [here](https://sdks.mediamelon.com/iOS/bitmovin/2.6.2/MediaMelonHarmonic.xcframework.zip)

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

    **Wrapper:** [here](https://sdks.mediamelon.com/iOS/bitmovin/2.6.1/BitmovinPlayerIntegrationWrapper.swift)

    **Framework:** [here](https://sdks.mediamelon.com/iOS/bitmovin/2.6.1/MediaMelonHarmonic.xcframework.zip)

[^3]: **Wrapper:** [here](https://sdks.mediamelon.com/iOS/bitmovin/2.5.0/BitmovinPlayerIntegrationWrapper.swift)

    **Framework:** [here](https://sdks.mediamelon.com/iOS/bitmovin/2.5.0/MediaMelonHarmonic.xcframework.zip)
