# MediaMelon iOS AVPlayer IMA SDK Integration Document

**Step 1:** [Set up MediaMelon SDK](#step-1-set-up-mediamelon-sdk)

**Step 2:** [Import Frameworks](#step-2-import-frameworks)

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

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

**Step 5:** [DAI & IMA Tracking Integration](#step-5-dai-and-ima-tracking-integration)

**Step 6:** [Errors and Warnings](#step-6-errors-and-warnings-important)

**Step 7:** [Report Additional Metadata Fields](#step-7-report-additional-metadata-fields)

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

**Step 9:** [Update Asset Information](#step-9-update-asset-information)

**Step 10:** [Additional Configurations](#step-10-additional-configurations)

[Release Notes](#release-notes)

### Step 1: Set up MediaMelon SDK

**Using Cocoapods:**

```swift
target 'SwiftDemo' do
  .
  pod 'MediaMelon-AVPlayer-Google-IMA-SDK', '~> 2.5.0'
  pod 'GoogleAds-IMA-iOS-SDK'
end
```

{% hint style="info" %}
The `MediaMelon-AVPlayer-Google-IMA-SDK` pod includes a dependency on the `MediaMelon-Google-IMA-SDK` framework pod. This dependency framework supports both iOS and tvOS platforms.&#x20;

Check the latest available version of `MediaMelon-Google-IMA-SDK` [here](https://docs.mediamelon.com/mediamelon-sdk-integration/ios/mediamelon-ios-custom-sdk-integration-document#release-notes).
{% endhint %}

### Step 2: Import Frameworks

```swift
import MediaMelonIMA
import MediaMelon_AVPlayer_Google_IMA_SDK
```

### Step 3: **Register and Initialize** MediaMelon SDK

#### Step 3.1: Set SDK Registration Information:

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

{% 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 3.2: Report Application Information:

```swift
AVPlayerIntegrationWrapper.shared.reportAppData(appName: "APP_NAME", appVersion: "APP_VERSION")
AVPlayerIntegrationWrapper.shared.reportAppSessionID(appSessionId: "APP_SESSION_ID")
```

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

```swift
AVPlayerIntegrationWrapper.shared.reportExperimentName(experimentName: "EXPERIMENT_NAME")
AVPlayerIntegrationWrapper.shared.reportSubPropertyID(subPropertyId: "SUB_PROPERTY_ID") 
```

#### Step 3.4: Set Content Metadata and Initialize Session:

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

AVPlayerIntegrationWrapper.shared.reportViewSessionID(viewSessionId: "VIEW_SESSION_ID")
AVPlayerIntegrationWrapper.initializeAssetForPlayer(assetInfo: assetInfo, registrationInformation: registrationInfo, player: player, isLive: <Bool>)

// Create the Ad Manager Delegate that will be used for MediaMelon SDK  
self.mmAdManagerDelegate = MMIMAAdManager.sharedManager
```

{% 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. Refer to [Custom Metadata Configuration Guide](https://docs.mediamelon.com/mediamelon/smartsight-player-sdk-integration/ios/broken-reference).
{% endhint %}

<details>

<summary>Example Setup</summary>

In the case of Google DAI, we use `IMALiveStreamRequest` or `IMAVODStreamRequest` to obtain a Live or VOD stream, respectively. The internal URL provided to AV Player needs to be given to the MM SDK during the initialization call. This can be obtained as follows:

```swift
 var mmSDKInitialised: Bool = false
 @objc func handleAVPlayerAccess(notification: Notification) {
        guard let playerItem = notification.object as? AVPlayerItem,
            let lastEvent = playerItem.accessLog()?.events.last else {
            return
        }
        guard let indicatedStream = lastEvent.uri else { return }
        var urlComps = urlString.components(separatedBy: "/")
        urlComps.removeLast()
        var streamComps = indicatedStream.components(separatedBy: "/")
        streamComps.removeLast()
        
        if urlComps != streamComps && !mmSDKInitialised {    
            self.mmSDKInitialised = true
            /**
                Initialize the MediaMelon SDK here. 
                Use indicatedStream for the STREAM_URL variable in MM SDK
            */
        }
    }
```

</details>

### Step 4: Additional Custom Metadata

Check the custom metadata configuration in the [SmartSight](https://smartsight3.mediamelon.com/settings) and report accordingly. If the custom tags are not configured, please configure and use them accordingly.&#x20;

Use this method to report any additional metadata that doesn’t fall under predefined metadata fields. This provides flexibility to send custom, business, or platform-specific information to the SDK.

```swift
AVPlayerIntegrationWrapper.shared.reportCustomMetadata(key: "KEY", value: "VALUE")
```

### Step 5: DAI & IMA Tracking Integration

#### Step 5.1: DAI MediaMelon Delegate Integration

```swift
class ViewController: UIViewController, IMAStreamManagerDelegate, IMAAdsLoaderDelegate {
    var mmAdManagerDelegate: MMAdManagerDelegate?
    var streamManager: IMAStreamManager?
  
    func adsLoader(_ loader: IMAAdsLoader!, adsLoadedWith adsLoadedData: IMAAdsLoadedData!) {
        self.streamManager = adsLoadedData.streamManager
        self.streamManager?.delegate = self
        self.streamManager?.initialize(with: nil)
    }
    
    func streamManager(_ streamManager: IMAStreamManager, didReceive error: IMAAdError) {
        print(error.debugDescription)
        mmAdManagerDelegate?.streamManager?(streamManager, didReceive: error)
    }
    
    func streamManager(_ streamManager: IMAStreamManager, didReceive event: IMAAdEvent) {
        mmAdManagerDelegate?.streamManager?(streamManager: streamManager, didReceive: event)
    }
}
```

#### Step 5.2: IMA MediaMelon Delegate Integration&#x20;

```swift
class PlayerContainerViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
    var mmAdManagerDelegate: MMAdManagerDelegate?
    private var adsManager: IMAAdsManager?
    
    // used for getting ads information and for identifying events such as started, first quartile, mid, clicked, skipped, paused, complete etc.
    func adsManager(_ adsManager: IMAAdsManager, didReceive event: IMAAdEvent) {
        mmAdManagerDelegate?.adsManager?(adsManager: adsManager, didReceive: event)
    }
    
    // used for reporting ads error. 
    func adsManager(_ adsManager: IMAAdsManager, didReceive error: IMAAdError) {
        mmAdManagerDelegate?.adsManager?(adsManager, didReceive: error)
    }
    
    // used for reporting ads requested event.
    func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
        mmAdManagerDelegate?.adsLoader?(loader, adsLoadedWith: adsLoadedData)
    }
    
    // used for reporting ads error.
    func adsLoader(_ loader: IMAAdsLoader, failedWith adErrorData: IMAAdLoadingErrorData) {
        mmAdManagerDelegate?.adsLoader?(loader, failedWith: adErrorData)
    }
}
```

### Step 6: Errors and Warnings (Important)

The SDK provides two ways to report errors: automatic error capture and manual error reporting via API.

⚙️ **Default Behavior (Auto Error Capture):**

By default, the SDK automatically listens to and captures player errors that occur *after the stream has loaded*. SDK will classify the errors based on severity.

{% hint style="info" %}

> ⚠️ Note: Errors that occur **before or during stream loading** are not captured automatically by the SDK, as they fall outside the player’s event lifecycle. Use the error and warning APIs below to manually report such issues.
> {% endhint %}

🚫 **Disabling Auto Error Capture:**

If you prefer to handle error reporting manually, you can disable this automatic behavior by calling:

```swift
AVPlayerIntegrationWrapper.shared.disableAutoErrorCapture()
```

{% hint style="info" %}

> ⚠️ When disabled, the SDK will not listen for any player-generated errors. You will be responsible for reporting all errors & warnings manually using the APIs described below.
> {% endhint %}

**🛠️ Manual Error Reporting APIs:**

Use these APIs to custom report errors and warnings to the SDK—especially for errors that occur **before or during stream loading**, or when auto-capture is disabled.

🔴 **Report Fatal Error:**

All errors reported via reportError are treated as **fatal**.

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

🟠 **Report Warning (Non-Fatal):**

All warnings reported via reportWarning are treated as non-fatal and will be tracked accordingly.

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

### Step 7: Report Additional Metadata Fields

#### Step 7.1: CDN:

Report the name or identifier of the Content Delivery Network (CDN) used for streaming. This helps track performance and quality across different CDNs.

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

#### Step 7.2: Stream Information:

Report key stream attributes that describe the encoding and delivery method.

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

#### Step 7.3: Player Resolution:

Report the width and height of the player window (in pixels). This is useful to understand playback size and user experience across different screen sizes or platforms.

```swift
AVPlayerIntegrationWrapper.shared.reportPlayerResolution(width: <player_width>, height: <player_height>)
```

#### Step 7.4: Report Stream Fallback Event

Report fallback event in case the primary manifest URL fails and falls back on the secondary manifest.

```swift
AVPlayerIntegrationWrapper.shared.reportFallbackEvent(fallbackManifestURL: "FALLBACK_URL", description: "DESCRIPTION")
```

### Step 8: Cleaning up the SDK Session

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

However, in some error cases, like network reachability issues, the error notification is delayed. And 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.

We recommend cleaning up the SDK session after playback completes or when the player lifecycle is complete. Missing to clean up the SDK session, might playtime, and session end time.
{% endhint %}

```swift
AVPlayerIntegrationWrapper.cleanUp()
```

### Step 9: Update Asset Information

To update the asset information during a content change or a live session, use the `changeAssetForPlayer` method as shown below. Whenever the asset information is updated, a new SDK session will be initialised. Please note either `changeAssetForPlayer` or `initializeAssetForPlayer` should be called not both.

If  Asset Information needs to be updated dynamically during the live session without re-initiating the player, then the `updateAssetInfo` API can be used to update the new AssetInfo

{% hint style="info" %}
The new Asset Info Object will override the previous values. Hence, set all the necessary fields every time this API is called, including all **Custom Tags.**
{% endhint %}

```swift
// Create a new assetInfo object with the values that need to be updated
let newAssetInfo = MMAssetInformation(assetURL: "STREAM_URL", assetID: "ASSET_ID", assetName: "ASSET_NAME", videoId: "VIDEO_ID")
newAssetInfo.setContentType("CONTENT_TYPE")
newAssetInfo.setDrmProtection("DRM_PROTECTION")
newAssetInfo.setEpisodeNumber("EPISODE_NUMBER")
newAssetInfo.setSeriesTitle("SERIES_TITLE")
newAssetInfo.setSeason("SEASON")
newAssetInfo.setGenre("GENRE")

AVPlayerIntegrationWrapper.changeAssetForPlayer(assetInfo: newAssetInfo, player: player)
```

### Step 10: Additional Configurations

#### Step 10.1: Disable manifest fetch by the SDK (Optional)

If your workflow limits access to the manifest from both the player and the MediaMelon Player SDK at the same time, you have the option to prevent manifest fetching by using the `disableManifestsFetch` method calling it before initialization.

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

#### Step 10.2: Enable or Disable SDK Log Trace

To enable the SDK log trace, use the following API call: enableLogTrace.

```swift
AVPlayerIntegrationWrapper.shared.enableLogTrace(logStTrace: true)
```

### Release Notes

<details>

<summary>Current Release</summary>

#### v2.5.0[^1]

* Combined iOS and tvOS frameworks into a single xcframework.
* Added App Session ID metadata fields.
* Updated Base Player Information reporting.
* Added `CDN_CHANGE` event.
* Added Ad buffering tracking for IMA and DAI.

</details>

Dependency Framework Releases: [MediaMelon-Google-IMA-SDK](https://docs.mediamelon.com/mediamelon-sdk-integration/ios/mediamelon-ios-custom-sdk-integration-document#release-notes)

***

<details>

<summary>Previous Releases</summary>

#### v2.4.0[^2]

* Fixed the DRM protection reset issue.
* Added Stream Information API.

</details>

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

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