VO Player iOS Integration Guide with SSAI

This guide provides detailed instructions on integrating the MediaMelon SDK into the iOS VO Player.

Prerequisites:

  1. VoPlayer iOS Sample Player.

  2. MediaMelon SmartSight SDK Framework.

  3. MediaMelon VOPlayer Swift adapter.

  4. MediaMelon-assigned Customer ID

<CUSTOMER_ID> is your MediaMelon-assigned Customer ID. If you do not know your Customer ID contact MediaMelon at support@mediamelon.com

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.

  • 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 MediaMelon-VOPlayer-SSAI-iOS 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.

import MMSmartStreamingSDK 

Create a new function setMMSmartStreaming as below and add it into PlayBackViewController.swift.

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.

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.

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


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.

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 stop the SSAI Ad Manager

To stop the SSAI Ad Manager, use the below code snippet in PlayBackViewController.swift file.

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

VariableDescription

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.

Last updated