-jio-start-block-type-2
-jio-style-title
JioReel, also called as Jio SSAI(Server-side ad insertion) is a combination of manifest manipulation, ad server communication, and ad bitrate and resolution normalization, all of which happens on the server-side before presenting a manifest to clients. Server-side ad insertion may also be referred to as dynamic ad insertion, or ad stitching.
Complete GETTING STARTED section and INITIALIZE SDK section before starting this section.
-jio-style-title
• Use our JioSSAIManager class to use the main APIs of the SDK for quick development from Publisher side.
• Initialize the JioSSAIManager to your viewcontroller & confirm to JIOSSAIAdEvents protocol named JioSSAIAdEventsProtocol
• View url and customer meta data can be provided by initializer method as describe below.
-jio-style-title
Example
viewUrl = "https://live-jio.serverside.ai/hls/view/627b64dc6c6e-4d9b-bf8f-f5042aa09da8?api-key=811ea138-1b89-4567-ab23-6887645a29c6"
customerMetaData = ["lt": "55"]
JioSSAIManager.shared.initializeJioSSAIAdManager(viewUrl: viewUrl, metadata: customerMetaData, requestTimeout: 8)
JioSSAIManager.shared.delegate = self
-jio-style-title
Please call set app’s AVPlayer to fire ad trackers
let player = AVPlayer()
JioSSAIManager.shared.setPlayer(avPlayer: player)
-jio-style-title
Use setMetadataGroup API to set Ad metadata info on JioSSAIManaget to process EXT-X-DATE-RANGES before playing AVPlayer.
func metadataCollector(_ metadataCollector: AVPlayerItemMetadataCollector,
didCollect metadataGroups: [AVDateRangeMetadataGroup],
indexesOfNewGroups: IndexSet,
indexesOfModifiedGroups: IndexSet) {
JioSSAIManager.shared.setMetadataGroup(metaData:
metadataGroups)
}
-jio-style-title
Call stop() method in order to stop SSAI listening to player metadata
JioSSAIManager.shared.stop()
-jio-style-title
Please call handleAdClick() method along with a bool whether it is primary or not on clicking CTA button call with true if the button is primary or else false
func secondaryCtaBtnClicked(_ sender: Any) {
JioSSAIManager.shared.handleAdClick(isPrimaryCTABtn: false)
}
-jio-style-title
-jio-style-title
onAdMediaReady
This delegate is used to know that SSAI media and ready and after this we need setup player & use preparePlayerForMetaDataCollection
func onSSAIMediaReady(mediaUrl: URL) {
mediaURL = mediaUrl playerSetup()
}
-jio-style-title
onAdMediaStart
This method called whenever any event triggered this consist of Ad event name and Ad Event data.
func onSSAIAdMediaStart (adMetaData: AdDataModel)
-jio-style-title
onAdMediaEnd
This method called once the entire ad list is played for the current ad break.
func onSSAIAdBreakCompleted (){
}
-jio-style-title
onAdError
This method called whenever the view api fails.
func onSSAIAdError (error: Error){
}
-jio-style-title
onAdChange
Whenever an ad is changed in case of multi ads, below delegate method is called
func onSSAIAdChanged(adMetaData: adDataModel){
}
-jio-style-title
SSAI companion Ad API
This method is used to display both single and multi containers using the provided adSlotId and container arrays.
JioSSAIManager.shared.showCompanionAds(adSlotId:[String], companionContainers: [UIView])
-jio-style-title
Below delegate method will be called on companion life cycle.
func onCompanionError (error: JioAdError, container: UIView) {
}
func onCompanionClose (container: UIView) {
}
func onCompanionClick () {
}
func onCompanionRender(container: UIView) {
}
-jio-style-title
import UIKit
#if os(tvOS)
import JioAdsFramework
#else
import JioAdsFramework
#endif
import AVKit
import AVFoundation
protocol JioSSAIWrapperProtocol: AnyObject {
func onAdMediaStart(adMetaData: JioAdDataModel)
func onStreamReady(streamUrl: URL)
func onAdMediaEnd()
func onAdError(error: Error)
func onAdChange(adMetaData: JioAdDataModel)
func onSSAICompanionAdFailedToLoad(error: JioAdError, container: UIView)
func onCompanionClose(container: UIView)
func onSSAICompanionAdRender(container: UIView)
func onSSAICompanionClick()
func onAdBreakDateRanges(adBreaks: [AdBreakDateRange])
}
extension JioSSAIWrapperProtocol {
func onAdBreakDateRanges(adBreaks: [AdBreakDateRange]) {}
}
class JioSSAIWrapper: NSObject {
private var avPlayer: AVPlayer?
public static let shared = JioSSAIWrapper()
var metadataCollector: AVPlayerItemMetadataCollector!
var playerItem: AVPlayerItem!
var timeObserver: Any?
weak var jioSSAIWrapperDelegate: JioSSAIWrapperProtocol?
private override init() {
}
public func initializeJioSSAIWrapper(viewUrl: String, metadata: [String:Any]?, requestTimeout: Double?, streamType: StreamType?, playBackType: PlayBackType?) {
JioSSAIManager.shared.delegate = self
// JioSSAIManager.shared.companionDelegate = self
JioSSAIManager.shared.setStreamType(streamType ?? .live)
JioSSAIManager.shared.setPlayBackType(playBackType ?? .sessionUrl)
JioSSAIManager.shared.initializeJioSSAIAdManager(viewUrl: viewUrl,
metaData: metadata,
requestTimeout: requestTimeout)
}
public func stop() {
JioSSAIManager.shared.stop()
removePeriodicTimeObserver()
}
func removePeriodicTimeObserver() {
// If a time observer exists, remove it
if let token = timeObserver {
avPlayer?.removeTimeObserver(token)
timeObserver = nil
SDKLog("SSAI | Time observerRemoved")
}
}
public func preparePlayerForMetaDataCollection(player: AVPlayer, mediaUrl: URL) {
prepareToPlay(player: player, mediaUrl: mediaUrl)
}
public func handleAdClick(isPrimaryCTABtn: Bool) {
JioSSAIManager.shared.handleAdClick(isPrimaryCTABtn: isPrimaryCTABtn)
}
public func setCompanionsAds(companions: [JioAdCompanion], delegate: JioCompanionAdviewProtocol) {
#if !os(tvOS)
JioSSAIManager.shared.setCompanions(companions: companions, delegate: delegate)
#endif
}
}
extension JioSSAIWrapper: JioSSAIAdEventsProtocol {
func onAdMediaStart(adMetaData: JioAdDataModel) {
self.jioSSAIWrapperDelegate?.onAdMediaStart(adMetaData: adMetaData)
}
func onStreamReady(streamUrl: URL) {
self.jioSSAIWrapperDelegate?.onStreamReady(streamUrl: streamUrl)
}
func onAdMediaEnd() {
self.jioSSAIWrapperDelegate?.onAdMediaEnd()
}
func onAdChange(adMetaData: JioAdDataModel) {
self.jioSSAIWrapperDelegate?.onAdChange(adMetaData: adMetaData)
}
func onAdError(error: Error) {
self.jioSSAIWrapperDelegate?.onAdError(error: error)
// self.jioSSAIWrapperDelegate?.onStreamReady(streamUrl: URL(string: "https://mercury.akamaized.net/jioads/ssai/vodManifest.m3u8")!)
}
func onAdBreakDateRanges(adBreaks: [AdBreakDateRange]) {
self.jioSSAIWrapperDelegate?.onAdBreakDateRanges(adBreaks: adBreaks)
}
}
extension JioSSAIWrapper: JioSSAICompanionAdProtocol {
func onCompanionClick() {
self.jioSSAIWrapperDelegate?.onSSAICompanionClick()
}
func onCompanionError(error: JioAdError, container: UIView) {
self.jioSSAIWrapperDelegate?.onSSAICompanionAdFailedToLoad(error: error, container: container)
}
func onCompanionClose(container: UIView) {
self.jioSSAIWrapperDelegate?.onCompanionClose(container: container)
}
func onCompanionRender(container: UIView) {
self.jioSSAIWrapperDelegate?.onSSAICompanionAdRender(container: container)
}
}
extension JioSSAIWrapper: AVPlayerItemMetadataCollectorPushDelegate, AVPlayerItemMetadataOutputPushDelegate {
func prepareToPlay(player: AVPlayer, mediaUrl: URL) {
metadataCollector = AVPlayerItemMetadataCollector()
metadataCollector.setDelegate(self, queue: DispatchQueue.main)
playerItem = AVPlayerItem(url: mediaUrl)
playerItem.add(metadataCollector)
player.replaceCurrentItem(with: playerItem)
addPlayerErrorObserver()
avPlayer = player
#if true
JioSSAIManager.shared.setPlayer(avPlayer: player)
#else
timeObserver = player.addPeriodicTimeObserver(forInterval: CMTime(seconds: Double(0.5),
preferredTimescale: 2),
queue: .global(qos: .background),
using: {[weak self] _ in
guard let self = self else { return }
JioSSAIManager.shared.playerTimeUpdated(time: self.avPlayer?.currentItem?.currentDate())
})
#endif
}
func addPlayerErrorObserver() {
NotificationCenter.default.addObserver(forName: .AVPlayerItemNewErrorLogEntry,
object: playerItem,
queue: .main) { [weak self] _ in
SDKLog("SSAI avplayer error comment = \(String(describing: self?.playerItem?.errorLog()?.events.last?.errorComment))")
SDKLog("SSAI avplayer Error log = \(String(describing: self?.playerItem.errorLog()))")
SDKLog("SSAI avplayer Error complete = \(String(describing: self?.playerItem.error))")
}
}
func metadataCollector(_ metadataCollector: AVPlayerItemMetadataCollector,
didCollect metadataGroups: [AVDateRangeMetadataGroup],
indexesOfNewGroups: IndexSet,
indexesOfModifiedGroups: IndexSet) {
#if true
let _ = JioSSAIManager.shared.setMetadataGroup(metaData: metadataGroups)
#else
let _ = JioSSAIManager.shared.setMetadataGroup(metaData: metadataGroups, time: avPlayer?.currentItem?.currentDate())
#endif
}
// func metadataOutput(_ output: AVPlayerItemMetadataOutput, didOutputTimedMetadataGroups groups: [AVTimedMetadataGroup], from track: AVPlayerItemTrack?) {
// print("metadataOutCalled")
// }
}
-jio-end-block-type-2