> For the complete documentation index, see [llms.txt](https://docs.mediamelon.com/mediamelon-nowtilus-ssai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.mediamelon.com/mediamelon-nowtilus-ssai/mediamelon-player-sdk-ios/vo-player-ios-integration-guide-with-ssai.md).

# VO Player iOS Integration Guide with SSAI

### Prerequisites: <a href="#prerequisites" id="prerequisites"></a>

1. VoPlayer iOS Sample Player.
2. MediaMelon SmartSight SDK Framework.
3. MediaMelon VOPlayer Swift adapter.
4. MediaMelon-assigned Customer ID

{% hint style="info" %}
\<CUSTOMER\_ID> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at [support@mediamelon.com](http://40mediamelon.com/)
{% endhint %}

### Step 1: **MMSmartStreaming SDK Framework and VOPlayer wrapper**

* Download the Mediamelon VO Player adapter from the below path and add it to the Swift application project.

{% hint style="info" %}
VOPlayerIntegrationWrapper: <https://mediamelon-builds.s3.amazonaws.com/MM-RELEASE-BUILDS/SDK_RELEASES/iOS/2024-04-24/VOPlayerIntegrationWrapper.swift>
{% endhint %}

* Add the MMSmartStreaming SDK Framework using Cocoapods as shown below. Navigate to your project folder using the terminal, if you don't have CocoaPods installed, Please install it using the below commands in the terminal.

```
sudo gem install cocoapods
pod init
touch Podfile
open Podfile
```

Add the <mark style="color:orange;">`MediaMelon-VOPlayer-SSAI-iOS`</mark> pod using the below lines in your Podfile.

```
target '<SampleProject_name>' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!
  
  pod 'MediaMelon-VOPlayer-SSAI-iOS'
  
  # Pods for <SampleProject_name>
end
```

Then install the pod by giving `pod install`

* Add the VOPlayer framework and its dependencies to the Xcode project

### **Step 2: Integrate MediaMelon Code to iOS Sample Player App**

The player application must register the SDK and provide player information once when the application launches. Please note that the values provided in this integration step persist across video sessions. This is typically done when the player itself is initialized.

Import the following in the **PlayBackViewController**.swift.

```swift
import MMSmartStreamingSDK 
```

Create a new function `setMMSmartStreaming` as below and add it into **PlayBackViewController.**&#x73;wift.

{% hint style="info" %}
**Note:**

Please provide the exact correct details in all fields like CUSTOMER\_ID, ASSET\_ID, ASSET\_TITLE, VIDEO\_ID, PLAYER\_BRAND, PLAYER\_MODEL, PLAYER\_VERSION, PLAYER\_NAME, DOMAIN\_NAME, SUBSCRIBER\_ID, SUBSCRIBER\_TYPE & SUBSCRIBER\_TAG.\
\
This data helps in debugging through MediaMelon SmartSight if anything goes wrong.
{% endhint %}

```swift
private func setMMSmartStreaming(hlsURLStr: String, vastUrlStr: String) {
        
        let assetInfo = MMAssetInformation(assetURL: hlsURLStr, assetID: "ASSET_ID", assetName: "ASSET_NAME", videoId:"VIDEO_ID")
        assetInfo.setQBRMode(.QBRModeDisabled, withMetaURL: nil)
        assetInfo.addCustomKVP("KEY1", "VALUE1")
        assetInfo.addCustomKVP("KEY2", "VALUE2")
        assetInfo.setContentType("CONTENT_TYPE")
        assetInfo.setGenre("GENRE")
        assetInfo.setEpisodeNumber("EPISODE_NUMBER")
        assetInfo.setSeriesTitle("SERIES_TITLE")
        assetInfo.setDrmProtection("DRM_PROTECTION")
        assetInfo.setSeason("SEASON")
        
        let registrationInfo = MMRegistrationInformation(customerID: "CUSTOMER_ID", playerName: "PLAYER_NAME")
        registrationInfo.setSubscriberInformation(subscriberID: "SUBSCRIBER_ID", subscriberType: "SUBSCRIBER_TYPE", subscriberTag: "SUBSCRIBER_TAG")
        registrationInfo.setPlayerInformation(brand: "PLAYER_BRAND", model: "PLAYER_MODEL", version: "PLAYER_VERSION")
        registrationInfo.setDomain("DOMAIN_NAME")
        
        VOPlayerIntegrationWrapper.shared.reportAppData(appName: "APP_NAME", appVersion: "APP_VERSION")
        VOPlayerIntegrationWrapper.shared.reportDeviceMarketingName(deviceMarketingName: "DEVICE_MARKETING_NAME")
        VOPlayerIntegrationWrapper.shared.reportVideoQuality(videoQuality: "VIDEO_QUALITY")
        
        VOPlayerIntegrationWrapper.initializeAssetForPlayer(assetInfo: assetInfo, registrationInformation: registrationInfo, player: self.voPlayer)
        
        VOPlayerIntegrationWrapper.shared.initialiseSSAIAdManager(mediaUrl: hlsURLStr, vastUrl: vastUrlStr, isLive: isLive, vodResponseData: self.vodResponseData)//"".data(using: .utf8)!
        VOPlayerIntegrationWrapper.shared.mmssaiManagerDelegate = self
}
```

Call “`setMMSmartStreaming`“ in function preparePlayer() as shown below. Refer `getURLDetails` function in the sample application to get the mediaURL and AD Data from the curl request for both live and VoD streams. If the stream is VoD, set the `isLive` variable to `false`. If the stream is Live, set the `isLive` variable to `true`. &#x20;

```swift
func preparePlayer() {
        if voPlayer == nil {
            voPlayer = VOPlayer()
            voPlayer!.add(self)
            voFlat360Manager = voPlayer!.getFlat360Manager()
        }       
        ..
        ..
        // NOTE: GET Media URL and VAST URL from Nowtilus SSAI URL 
        // Set Media URL to Player 
         
          self.voPlayer!.prepareToPlay()
          self.voPlayer!.play()
          
        // Set Media URL and VAST URL from Nowtilus SSAI URL to mediamelon SDK 
          self.setMMSmartStreaming(hlsURLStr: mediaUrl, vastUrlStr: vastUrl)
  
          // post a notification to menuViewController to set voPlayer
        }
    }
}
```

### **Step 3:** To Add delegates to get the Ad events from SSAIAdManager

```swift

class PlayBackViewController: UIViewController, VOFairPlayLicenseRequestDelegate, UITableViewDelegate, UITableViewDataSource, ContainerDelegate, MediaBrowserCellDelegate, GCKUIMiniMediaControlsViewControllerDelegate, DownloaderControllerDelegate, VOAdBannerViewEventsFeedbackDelegate, CXCallObserverDelegate, GCKSessionManagerListener, GenericAdProtocol, MMSSAIManagerDelegate, VOPlayerObserver {
    
    func notifyMMSSAIAdEventsWithTimeline(eventName: MMSSAIAdSate, adTimeline: [MMSSAIAdDetails])
    {
        
        if (eventName == MMSSAIAdSate.adCueTimelineAdded)
        {
            print("---------------------------------------------------")
            print(" Ad Timeline Added via Vast")
            print("---------------------------------------------------")
            
           // below two lines represents how to access adStartPosition and adEndPosition from adTimeline Array
            print("Ad Start Position = ", adTimeline[0].adStartPosition)
            print("Ad End Position = ", adTimeline[0].adEndPosition)
   
        }
    }
    
    
    func notifyMMSSAIAdEvents(eventName: MMSSAIAdSate, adInfo: MMSSAIAdDetails) {
        
        if (eventName == MMSSAIAdSate.adPlaying)
        {
            print ("Ad progress ", ((VOPlayerIntegrationWrapper.getAdPlaybackTime(adInfo: adInfo)*100)/VOPlayerIntegrationWrapper.getAdDuration(adInfo: adInfo)))
            self.skipOffset = Int( VOPlayerIntegrationWrapper.getAdDuration(adInfo: adInfo) - VOPlayerIntegrationWrapper.getAdPlaybackTime(adInfo: adInfo) + 1)
        }
        else
        {
            print("---------------------------------------------------")
            print(" Ad Id :",VOPlayerIntegrationWrapper.getAdId(adInfo: adInfo))
            print(" Ad Title :",VOPlayerIntegrationWrapper.getAdTitle(adInfo: adInfo) )
            print(" Ad Index :",VOPlayerIntegrationWrapper.getAdIndex(adInfo: adInfo)," of ", VOPlayerIntegrationWrapper.getAdTotalAdsInPod(adInfo: adInfo) )
            print(" Ad Server :",VOPlayerIntegrationWrapper.getAdServer(adInfo: adInfo))
            print(" Ad Duration :",VOPlayerIntegrationWrapper.getAdDuration(adInfo: adInfo) )
            print(" Ad Position :",VOPlayerIntegrationWrapper.getAdPosition(adInfo: adInfo) )
            print(" Ad Event :",eventName )
            
            if ( eventName == MMSSAIAdSate.adImpression)
            {
                let clickURL = VOPlayerIntegrationWrapper.getClickThroughURL(adInfo: adInfo)
                let clickTrackingURL = VOPlayerIntegrationWrapper.getClickTrackingURL(adInfo: adInfo)
                print("Video Click URL:", clickURL)
                print("Video Click Tracking  URL:", clickTrackingURL)
            }
            print("---------------------------------------------------")
        }
    }
    
    ..
    ..
}
```

### Accessing the adTimeline array object

adTimeline array object (MMSSAIAdDetails) contains the following multiple MMSSAIAdDetails objects.&#x20;

```swift
MMSSAIAdDetails {
    adId: String                                 // contains the ad ID
    adTitle: String                              // contains the ad title
    adServer: String                             // contains the ad server (example: "nowtilus")
    adIndex: Int                                 // contains the ad index in the current adbreak (1 based index)
    adTotalAdsInPod: Int                         // contains the total number of ads received from the current vast response
    adDuration: Int64                            // contains the ad duration in seconds
    startTime: Int64                             // contains ad start time in epoch time format (milliseconds)
    endTime: Int64                               // contains ad end time in epoch time format (milliseconds)
    firstQuartile: Int64                         // contains the first quartile position of the ad (i.e. adStartTime + 25% of adDuration)
    midPoint: Int64                              // contains the midpoint position of the ad (i.e. adStartTime + 50% of adDuration)
    thirdQuartile: Int64                         // contains the third quartile position of the ad (i.e. adStartTime + 75% of adDuration)
    complete: Int64                              // contains the ad complete position (i.e. adStartTime + 100% of adDuration)
    adCurrentPlaybackTime: Int64                 // contains the ad progress in seconds
    position: String                             // contains the ad position ("PRE", "MID", "POST")
    active: Bool                                 // contains whether the ad is active or not (true or false)
    adState: String                              // contains the ad state (example: "READY", "START", "COMPLETE", "SKIPPED")
    streamType: String                           // contains the stream type (example: "HLS")
    isLinear: Bool                               // this is set to true
    adTrackerInfo: AdTrackerInfo?                // contains ad track info
    adImpressionsTemplates: [VastImpression]     // contains ad impression template details
    adTrackingEvents: [VastTrackingEvent]        // contains ad tracking event details
    adClickEvents: [VastVideoClick]              // contains click and clickthrough urls
    adSkipOffset : Int64                         // contains the skip offset
    adStartPosition: Int64                       // describes the ad start position relative to the program date time received in the first manifest
    adEndPosition: Int64                         // describes the ad end position relative to the program date time received in the first manifest
}
```

### Step 4: To s**top the SSAI Ad Manager**

To stop the SSAI Ad Manager, use the below code snippet in **PlayBackViewController.**&#x73;wift file.

```swift
VOPlayerIntegrationWrapper.shared.stopSSAIAdManager()
```

### List of Ad events

1. onCueTimelineAdded
2. onCueTimelineStart
3. onAdImpression
4. onAdStarted
5. onAdFirstQuartile
6. onAdMidpoint
7. onAdThirdQuartile
8. onAdProgress
9. onAdComplete
10. onCueTimelineEnd

| Variable         | Description                                                                                                                                                                         |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| PLAYER\_NAME     | String containing the player name (e.g. “VOPlayeriOS”).                                                                                                                             |
| CUSTOMER\_ID     | String containing your MediaMelon-assigned Customer ID.                                                                                                                             |
| SUBSCRIBER\_ID   | String containing your subscriber’s ID. If you do not use subscriber IDs, enter nil.                                                                                                |
| DOMAIN\_NAME     | String containing your section of your subscriber or assets. (Optional)                                                                                                             |
| SUBSCRIBER\_TYPE | String containing the subscriber type (e.g. “Free”, “Paid”). If you do not use subscriber types, enter nil.                                                                         |
| SUBSCRIBER\_TAG  | String containing additional subscriber-specific information. This is sent in clear (not hashed) to SmartSight and it is advised to not send sensitive information in this field.   |
| ASSET\_ID        | String containing Asset Id.                                                                                                                                                         |
| ASSET\_NAME      | String containing Asset Name.                                                                                                                                                       |
| VIDEO\_ID        | String containing your video’s ID. If you do not use videos IDs, enter null.                                                                                                        |
| PLAYER\_BRAND    | String containing the player brand.                                                                                                                                                 |
| PLAYER\_MODEL    | String containing the player model. For example - This could be a variant of player. Say name of third party player used by organisation. Or any human readable name of the player. |
| PLAYER\_VERSION  | String containing the player version.                                                                                                                                               |
