Bitmovin IOS v2.66(Nowtilus SSAI)
Step by step integration of the Mediamelon Player SDK with Nowtilus SSAI with Bitmovin Player 2.66
Step 0: Creating Bitmovin Player based media player application
Create a directory for integration by doing the following. Open the terminal, change directory to the home directory, and create a folder sampleintegration
cd ~/
mkdir sampleintegration
cd sampleintegration/
Pull the Sample Application from https://sdk.mediamelon.com/$CustomerID/iOS/SampleBitmovinPlayer_iOS_v2.66_<Cocoapod Version>_v<Core iOS SDK version>.zip
and unzip it
wget https://sdk.mediamelon.com/$CustomerID/iOS/SampleBitmovinPlayer_iOS_v2.66_<Cocoapod Version>_v<Core iOS SDK version>.zip
Get the sample app dependencies by changing the directory to the ~/sampleintegration/https://sdk.mediamelon.com/$CustomerID/iOS/SampleBitmovinPlayer_iOS_v2.66_<Cocoapod Version>_v<Core iOS SDK version>
and execute the following commands
Step 1: Building the MediaMelonSmartStreaming Framework
Execute the following two commands on the terminal in the folder ~/sampleintegration/SampleBitmovinPlayer_iOS_v2.66_<Cocoapod Version>_v<Core iOS SDK version>
sudo gem install cocoapods
pod init
touch Podfile
open Podfile
Edit the Podfile
target 'BasicPlayback' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
pod 'MMSmartStreamingSDK', git: 'https://bitbucket.org/mediameloninc/mmsmartstreamingios-genericpods.git', tag: '0.3.2'
source 'https://github.com/bitmovin/cocoapod-specs.git'
pod 'BitmovinPlayer','~>2.66'
# Pods for BasicPlayback
end
Finally, install the pod pod install
Step 2: Integrating the MediaMelonSmartStreaming Framework
There are five steps involved for integrating the MediaMelon Player SDK using the MediaMelonSmartStreaming Framework:
Importing the framework
Providing asset information for the content before starting the player and after creating its instance
Cleaning up the SDK integration session
Disable manifest fetching by the SDK
Initializing SSAI
Open the project file ~/sampleintegration/SampleBitmovinPlayer_v2.66_SSAI/BasicPlayback.workspace
in XCode and edit the file ViewController.swift
as mentioned below
1. Import Frameworks
import BitmovinPlayer
import MMSmartStreamingSDK
2. Provide Asset information
private func configureMMSDK(mediaURL: String, vastURL: String) {
let assetInfo = MMAssetInformation(assetURL: mediaURL, assetID: "RandomID", assetName: "Test Asset", videoId: "123456789")
assetInfo.setContentType("Movie") //Type of content (Movie / Special / Clip / Scene)
assetInfo.setDrmProtection("Fairplay") //Widevine, Fairplay, Playready etc. Unknown means content is protected, but protection type is unknown. For clear contents, do not set this field
assetInfo.setEpisodeNumber("testEpisode") //Sequence Number of the Episode (string).
assetInfo.setSeriesTitle("testSeries") //Title of the series
assetInfo.setSeason("testSeason") //Season For example - Season1,2,3 etc
assetInfo.setGenre("testGenre") //Genre of the content
// Optional custom metadata
assetInfo.addCustomKVP("CustomKVP1Key", "CustomKVP1Value")
assetInfo.addCustomKVP("CustomKVP2Key", "CustomKVP2Value")
assetInfo.setQBRMode(.QBRModeDisabled, withMetaURL: nil)
let resgistrato = MMRegistrationInformation(customerID: "200417809", playerName: "BitmovinPlayerTesting")
BitmovinPlayerIntegrationWrapper.setPlayerRegistrationInformation(registrationInformation: resgistrato, player: player)
BitmovinPlayerIntegrationWrapper.initializeAssetForPlayer(assetInfo: assetInfo, registrationInformation: resgistrato, player: player)
}
3. Cleaning up the SDK Session
BitmovinPlayerIntegrationWrapper.cleanUp()
5. Disable manifest fetching by the SDK
If your workflow restricts the manifest to be accessible from both player and the MediaMelon Player SDK simultaneously, then, you can disable the fetch of manifest via disableManifestsFetch()
in method _configureMMSDKwithURL()
private func configureMMSDKWithURL(mediaURL: String, vastURL: String) {
.
.
.
BitmovinPlayerIntegrationWrapper.cleanUp()
BitmovinPlayerIntegrationWrapper.disableManifestsFetch(disable: true)
BitmovinPlayerIntegrationWrapper.initializeAssetForPlayer(assetInfo: assetInfo, registrationInformation: registrationInfo, player: player)
}
5. Add the SSAIManagerDelegate
Add the SSAIManagerDelegate to the ViewController class in ViewController.swift
class ViewController: UIViewController, SSAIManagerDelegate
6. Initialize the SSAI Ad Manager
Initialize the SSAI Ad Manager to track the Ads and report Ad related metrics
private func configureMMSDK(mediaURL: String, vastURL: String) {
.
.
.
BitmovinPlayerIntegrationWrapper.shared.initialiseSSAIAdManager(mediaUrl: mediaURL, vastUrl: vastURL, isLive: true)
}
7. Create a new session and update the asset information
During playback updateAssetInfo can be used to create a new session and update the asset information. The usage can be seen in the updateAsset function in the ViewController
func updateAsset() {
let assetInfo = MMAssetInformation(assetURL: mediaURL, assetID: "RandomID", assetName: "Test Asset", videoId: "123456789")
assetInfo.setContentType("Movie") //Type of content (Movie / Special / Clip / Scene)
assetInfo.setDrmProtection("Fairplay") //Widevine, Fairplay, Playready etc. Unknown means content is protected, but protection type is unknown. For clear contents, do not set this field
assetInfo.setEpisodeNumber("testEpisode") //Sequence Number of the Episode (string).
assetInfo.setSeriesTitle("testSeries") //Title of the series
assetInfo.setSeason("testSeason") //Season For example - Season1,2,3 etc
assetInfo.setGenre("testGenre") //Genre of the content
assetInfo.addCustomKVP("CustomKVP1Key", "CustomKVPalue")
assetInfo.addCustomKVP("CustomKVP2Key", "CustomKVPValue")
assetInfo.setQBRMode(.QBRModeDisabled, withMetaURL: nil)
// Create a new session and update the Asset info
BitmovinPlayerIntegrationWrapper.updateAssetInfo(assetInfo: assetInfo, player: player)
}
8. Getting the mediaURL and vastURL from the Session Resolver URL
The session resolver URL as provided by Nowtilus needs to be used to generate the mediaURL and the vastURL. This is done in code as follows
private func getURLDetails(url: String, callback: @escaping (_ mediaUrl: String, _ vastUrl: String)->Void) {
let request = URLRequest(url: URL(string: url)!)
let session = URLSession(configuration: URLSessionConfiguration.default)
let task = session.dataTask(with: request) {(data, response, error) in
DispatchQueue.global().async {
if error != nil || data == nil {
print("Client error!")
return
}
guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode) else {
print("Server error!")
return
}
do {
print(String(data: data!, encoding: String.Encoding.utf8)!)
let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]
if let jsonDict = json {
var mediaUrl: String = ""
var vastUrl: String = ""
if let dataString = jsonDict["data"] as? String {
let stringArray = dataString.components(separatedBy: "?vast-data=")
if stringArray.count > 1 {
mediaUrl = stringArray[0]
if let decodedData = stringArray[1].replacingOccurrences(of: "3D", with: "=").base64Decoded() {
vastUrl = decodedData
}
callback(mediaUrl, vastUrl)
print("test")
}
} else {
if let mUrl = jsonDict["mediaURL"] as? String {
mediaUrl = mUrl
}
if let vUrl = jsonDict["vastURL"] as? String {
vastUrl = vUrl
}
callback(mediaUrl, vastUrl)
}
}
} catch {
print("parse JSON error: \(error.localizedDescription)")
}
print("parse Completed request: \(request.debugDescription)")
}
}
task.resume()
}
}
Call thenitialize the SSAI Ad Manager to track the Ads and report Ad related metrics. The mediaURL and vastURL is retur
func onDownloadFinished(_ event: DownloadFinishedEvent) {
var redirectedMediaURL: String?
if let redirectionLocation = event.lastRedirectLocation {
redirectedMediaURL = redirectionLocation.absoluteString
let tempUrl = redirectedMediaURL?.replacingOccurrences(of: "master.m3u8?sid=", with: "")
if let urlArr = tempUrl?.components(separatedBy: "&"), urlArr.count > 0 {
let vastUrl = urlArr[0] + "/vast.xml"
print(vastUrl)
if !isMMInitialised {
derivedMediaURL = redirectedMediaURL!
self.configureMMSDK(mediaURL: redirectedMediaURL!, vastURL: vastUrl)
isMMInitialised = true
}
}
}
if redirectedMediaURL == nil {
redirectedMediaURL = event.url.absoluteString
}
}
Last updated
Was this helpful?